React + Flux:将初始状态放入商店

React + Flux: Getting initial state into a store

我们最近从 Angular 切换到 React + Flux 来构建一个相当复杂的业务应用程序。

采用让一个容器组件将所有状态作为属性传递到组件树下的方法并不是为我们开发应用程序的实用方法,因为该应用程序使用类似页面的大模态。确实有足够的状态传递给模式,以便他们将数据加载到他们的商店中。

我遇到的问题是我需要将一些初始状态(作为道具传递)放入模态组件的商店中。在 this post 中,Facebook 的好人说当同步不是目标时,可以使用 props 作为初始状态。

这就是我目前将初始状态放入我的商店的方式:

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 反模式?

我觉得您使用 getInitialState() 来更改您的商店状态是不对的。您至少应该在 componentWillMount.

中这样做

我会在 componentWillMount 中触发一个操作并让商店处理程序更新商店的内部状态(这应该始终是不断变化的情况)。然后您的组件的商店更改处理程序可以使用您当前调用的任何数据 "initial state"

Reflux.listenTo 在您提供第三个参数时执行此操作,并且 Reflux.connect mixin 工厂(在引擎盖下使用 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>);
    }
});

正如其他发帖者所说,最好的办法是在 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 的回调尚未向调度程序注册。

初始化应该在向调度程序注册回调之后进行。

编辑:为清楚起见,initAuthors 可能看起来像这样:

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

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