Подтвердить что ты не робот

React + Flux: получение начального состояния в хранилище

Недавно мы перешли на React + Flux из Angular, чтобы построить довольно сложное бизнес-приложение.

Принимая подход к тому, что один компонент контейнера, который передает все состояние в качестве свойств вниз по дереву компонентов, не является практическим способом разработки приложения для нас, так как приложение использует большие страницы-подобные модалы. Достаточное состояние передается модально для их загрузки своих данных в свои магазины.

У меня есть проблема: мне нужно получить начальное состояние (переданное как реквизит) в хранилище модальных компонентов. В этот пост хорошие парни в Facebook говорят, что это нормально использовать реквизиты для начального состояния, когда синхронизация не является целью.

Вот как я получаю начальное состояние в моем магазине в настоящее время:

var ABC = React.createClass({
  ...  
  getInitialState: function() {
    return ABCStore.getInitialABCState(this.props.initialA);
  },
  ...

var ABCStore = Reflux.createStore({
  ...
  init: function() {
    _state = {
      a: null,
      b: 'B init',
      c: 'C init'
    };
  },

  getInitialABCState: function(initialA) {
    _state.a = initialA;
    return _state;
  },

  getABCState: function() {
    return _state;
  }
  ...

Я не уверен, что лучше всего сделать это, или это анти-шаблон Flux?

4b9b3361

Ответ 1

Мне кажется неправильным, что вы используете getInitialState() для изменения состояния своего магазина. Вы должны хотя бы сделать это в componentWillMount.

Я бы вызвал действие в componentWillMount и обработчик хранилища обновил внутреннее состояние хранилища (это всегда должно происходить в потоке). Затем ваш обработчик изменения компонента для хранилища может использовать все данные, которые вы в настоящее время вызываете в своем "начальном состоянии"

Ответ 2

Reflux.listenTo делает это, когда вы предоставляете третий аргумент и Reflux.connect mixin factory (который использует Reflux.listenTo под капотом ) обрабатывает это для вас автоматически. Вот пример:

var Actions = Reflux.createActions({"doIt"});

var Store = Reflux.createStore({
    listenables: [Actions],
    init: function() {
        this.state = "I like to";
    },
    onDoIt: function() {
        this.state = "Do it";
        this.trigger(this.state);
    },
    getInitialState: function() {
        return this.state;
    }
});

var DoItButton = React.createClass({
    mixins: [Reflux.connect(Store, "label")],
    onClick: function() {
        Actions.doIt();
    },
    render: function() {
        return (<div onClick={this.onClick}>{this.state.label}</div>);
    }
});

Ответ 3

Как и другие плакаты, самое лучшее, что нужно сделать, это запустить действие в componentWillMount. В ES6 это обычно делается с помощью constructor.

Ниже приведен пример того, как это сделать с ES6:

(обратите внимание, что AuthorActions.initAuthors() зависит от реализации, это просто пример, который может получить исходное состояние из базы данных. Самое главное, это действие должно отправить полезную нагрузку с начальным состоянием диспетчеру)

var _authors = [];
var AuthorStoreInstance;

class AuthorStore extends EventEmitter {

    constructor(props) {
        super(props);
    }

    init() {
        AuthorActions.initAuthors();
        this.emitChange();
    }

    addChangeListener(cb) {
        this.on(CHANGE_EVENT, cb);
    }

    removeChangeListener(cb) {
        this.removeListener(CHANGE_EVENT, cb);
    }

    emitChange() {
        this.emit(CHANGE_EVENT);
    }

    getAllAuthors() {
        return _authors;
    }

    addAuthor(author) {
        _authors.push(author);
        this.emitChange();
    }

    setAuthors(authors) {
        _authors = authors;
    }

};


AuthorStoreInstance = new AuthorStore();

Dispatcher.register((action) => {
    switch(action.actionType) {
        case ActionTypes.CREATE_AUTHOR:
            AuthorStoreInstance.addAuthor(action.author);
            break;
        case ActionTypes.INITIALIZE:
            AuthorStoreInstance.setAuthors(action.initialData.authors);
            break;

        default:
            //do nothing
    }
});

AuthorStoreInstance.init();

export default AuthorStoreInstance;

Обратите внимание, что функция init не является частью конструктора. Это связано с тем, что при построении authorStore обратный вызов для AuthorActions.initAuthors не был зарегистрирован диспетчером.

Инициализация должна произойти после регистрации обратных вызовов в диспетчере.

edit: Для ясности initAuthors может выглядеть примерно так:

initAuthors() {
    var authors = AuthorAPI.getAllAuthors();

    Dispatcher.dispatch({
        actionType: ActionTypes.INITIALIZE,
        initialData: {
            authors: authors
        }
    });
}