Statefull组件与可能异步的商店的交互

时间:2015-06-22 15:46:30

标签: reactjs reactjs-flux

我正在研究React Flux项目,其中异步交互是一项持续的事情,而且在反应生命周期方面我仍然有点不稳定。

在我的有状态组件中,我有一个getStateFromStores函数,如果store中没有状态,则返回false bool,否则返回状态。

正如我现在所说的那样,循环如下:

我的组件中有一个名为getState()的绑定函数(ES6反应类),它只调用getStateFromStores并检查返回值是否为false,如果不是,则调用带状态的setState()。

由于状态变化的通知可能来自不同的来源,我喜欢在一个地方声明逻辑(getState)

状态变化可能来自以下方面:

  • ComponentDidMount(我应该把它移到initialState吗?) 这是组件生命周期中发生的第一件事。 (除非我们的商店中已经存在状态,否则我们会得到错误的回报)

  • ComponentWillReceiveProps 如果在父组件中更改了状态,我们会通知组件它应该使用新的道具获取新状态。

  • 存储更改侦听器 当store具有新状态时,getState被调用作为回调(虽然有点问题,因为发出的原因可能是由于给定组件的调用而导致的 - 所以我可能实现onStoreChange作为回调,而后者又调用getState)

我正在玩一个叫做抓取的状态道具,我可以用来控制流量,但这有问题吗? - 因为每次我改变状态它都会触发渲染(?) - 我可以使用静态吗?

我想象以下内容; DidMount触发getState(),getState设置为true,现在所有其他的调用尝试都会因bool检查而失败。

然后我实现了一个resetState,它将状态恢复为默认状态(获取false),然后再次触发getState。

我将所有这些功能抽象为“高阶组件”

谢谢!

2 个答案:

答案 0 :(得分:2)

我采取了不同的方法。我发现编写React组件的一大优势是,您可以将组件视为一个独立的单元 - 具有自己的HTML,JavaScript,数据获取 - 甚至样式。它依靠Flux存储来跟踪数据,而不是将数据作为道具传递。

假设您有用户登录并收到一些信息。现在,让我们说用户想要管理他们的帐户。我们可以这样做......

<Account user_info={this.state.user_info} />

这样可以正常工作,但如果帐户知道user_id,那么帐户是否可以获得所需的user_info?这会引导我们......

<Account user_id={this.state.user_info.user_id}>

但是,真的,商店不知道登录用户是谁吗?毕竟,它是获取/存储数据的必要条件。那么为什么不呢......

<Account />

...让Account从商店获取所需数据 - 不需要user_id,因为商店已经知道登录用户。

无论如何,只是一种不同的思考方式。

答案 1 :(得分:1)

我发现在大多数情况下我的工作非常好,就是拥有一个根“控制器组件”。我们现在称它为Controller。它基本上就像React组件一样 - 但它的责任有点不同。

我认为这只是委托。唯一的责任是从商店获取数据(状态)并将其(作为道具)传递给其子组件,让他们完成所有工作。

这是通过将商店中的数据设置为Controller的状态来完成的。商店中的任何更改都会(仅)更新其状态Controller。由于状态作为道具传递给子项,因此商店中的更改将触发使用该数据重新呈现的所有子组件(如果必须)。

我尝试仅将相关数据传递给子组件,但不要太担心它们获取大量数据(或者关于一些额外的重新渲染)。

在实践中,Controller看起来像这样:

function getStateFromStores() {
    return {
        players: PlayerStore.getData(),
        cards: CardStore.getData()
    };
}

var Controller = React.createClass({
    getInitialState: function() {
        return getStateFromStores();
    },

    componentDidMount: function() {
        PlayerStore.addChangeListener(this._onChange);
        CardStore.addChangeListener(this._onChange);
    },

    componentWillUnmount: function() {
        PlayerStore.removeChangeListener(this._onChange);
        CardStore.removeChangeListener(this._onChange);
    },

    _onChange: function() {
        this.setState(getStateFromStores());
    },

    render: function() {
        return (
            <Component1 
                players={this.state.players}
                cards={this.state.cards}
            />

            <Component2
                players={this.state.players}
            />

            <Component3
                cards={this.state.players}
            />
        );
    }
});

module.exports = Controller;