TODO App 4. Store 만들기

이제 끝이 얼마 남지않았다.

store를 만들어보자.

파일이름은 comment-store.js이다.

var AppDispatcher = require('../dispatcher/app-dispatcher');

var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');

var comments = [];

var CommentStore = assign({}, EventEmitter.prototype, {

  emitChange: function() {
    this.emit('change');
  },

  addChangeListener: function(callback) {
    this.on('change', callback);
  },

  removeChangeListener: function(callback) {
    this.removeListener('change', callback);
  },

  getAll: function() {
    return comments;
  }
});

AppDispatcher.register(function(action) {

  switch(action.actionType) {

    case "CREATE_COMMENT":
      comments.push(action.comment);
      CommentStore.emitChange();
      break;

    default:
  }
});

module.exports = CommentStore;

Store는 데이터를 처리하는 로직을 담고 있기 때문에 다른 파일들 보다는 길다.

위부터 천천히 살펴보자.

var AppDispatcher = require('../dispatcher/app-dispatcher');

var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');

AppDispatcher를 가져오고 EventEmitter와 assign를 가져오는데

EventEmitter는 Store에 Observer Pattern을 구현하기위해 사용한다.

assign은 객체를 Merge하기위해 사용된다.

var comments = [];

comments 변수가 실제 comment 데이터가 담기는 배열이다.

이 변수는 클로저를 이용해서 가져오기 때문에 실제로 외부에서 comments에 바로 접근할 수 없다.

var CommentStore = assign({}, EventEmitter.prototype, {

  emitChange: function() {
    this.emit('change');
  },

  addChangeListener: function(callback) {
    this.on('change', callback);
  },

  removeChangeListener: function(callback) {
    this.removeListener('change', callback);
  },

  getAll: function() {
    return comments;
  }
});

실제 Store의 구현인데 assign를 사용하고 있다.

assign의 첫번째 인자는 빈 객체이고 두번째 인자는 Observer Pattern을 구현하기 위한 EventEmitter의 Prototype 객체이고 세번째 인자는 사용자가 정의한 객체 리터럴이다.

addChangeListener 메서드는 on메서드를 실행시켜주는데 on과 emitChange 메서드에 있는 emit은 EventEmitter의 Prototype에 있는 메서드이다.

on과 emit으로 Observer 패턴을 사용하고있다.

addChangeListener에 Callback을 넘겨서 change라는 이름의 이벤트가 발생하면 해당 Callback이 실행되도록 만든다.

removeChangeListener 메서드는 addChangeListener 메서드로 등록한 이벤트를 지워주는 메서드 이다.

그리고 getAll 메서드가 클로저로 실제 comment데이터에 접근하는 메서드이다.

이 메서드를 통해서 Store에서 comment를 얻어올 수 있다.

emitChange 메서드는 change메서드를 발생 시켜서 addChangeListener로 등록한 callback이 발생하도록 하는 메서드이다.

이렇게 Store를 모두 정의했다.

Store를 정의한 다음에는 Dispatcher에 등록을 해줘야 한다.

그래야 Action이 발생하면 Dispatcher에게 Action을 받을 수 있기 때문이다.

AppDispatcher.register(function(action) {

  switch(action.actionType) {

    case "CREATE_COMMENT":
      comments.push(action.comment);
      CommentStore.emitChange();
      break;

    default:
  }
});

위 부분이 Dispatcher에 Store를 등록하는 메서드이다.

보면 AppDispatcher.register 메서드에 Callback을 등록하는 형태이다.

그리고 Callback은 action을 파라미터로 받고 있다.

우리가 계속 애기하던 내용 그대로이다.

내부에서는 Switch문으로 Action의 actionType을 기준으로 로직을 분기하고 있다.

"CREATE_COMMENT"이면 클로저로 에 comments에 접근하여 comment를 push해주고 CommentStore.emitChange();를 실행하여 Store에 변화가 일어났음을 알린다.

그러면 Store에 addChangeListener로 등록된 Callback이 실행된다.

이렇게 Store를 작성해 보았다.

어떤가? 그래도 Flux의 흐름이 눈에 들어오지 않는가?