React + Flux - 应该将数据存储在组件状态还是props?

Guy*_*her 25 reactjs reactjs-flux refluxjs

如果flux存储是一个维护数据状态的单例,为什么组件在访问存储时使用setState而不是setProps?这不仅仅意味着我开始在两个(或更多)位置保存应用程序状态吗?

Flux/React文档和示例似乎都指向setState作为首选解决方案,但我与一些同事在工作中进行了一次有趣的对话,并想知道是否有其他人遇到过此问题

编辑:你可以在这个网址中看到我在说什么:https: //github.com/facebook/flux/blob/master/examples/flux-chat/js/components/ThreadSection.react.js

注意ThreadSection是一个子组件,它直接从商店获取数据并将其用作状态.

如果你遵循React"方式"我会期望状态由商店管理 - 而不是子组件.

我们想到的解决方案是获取顶级组件中的所有商店(作为props),并根据需要将它们传递给子组件.但这很快变得相当丑陋.

我们这样做是因为setProps不适用于子组件

Ryg*_*ygu 43

了解您应该有两种组件.有状态组件和视图组件.

有状态组件可以具有3种状态:初始状态,用户输入状态和数据存储状态.

有状态的组件就像您正在组装的"小部件"中的小入口点.对于下游依赖或数据注入,不再有单个应用程序范围的入口点,因为所有这些窗口小部件都有自己独立的生命周期.这就是他们自己需要访问和收听商店的原因.

除了行为属性之外,有状态组件不会通过上游属性接收实际数据.

有状态组件管理自己的状态并将其传递给子级以通过下​​游属性进行渲染.

有状态组件通常不直接呈现html DOM元素本身.它们更像是MVC中的控制器,并使用其他dumber组件(如MVC中的视图)来实际呈现DOM元素.

Dumber组件类似于视图,因此它们只包含用于呈现DOM元素的逻辑.将它们视为handlebars.js模板,它们只接收属性,并简单地将它们呈现为DOM元素,可能带有循环等.它们是无状态渲染器.

希望这能回答你的问题.


yar*_*den 7

根据正式文档,商店应该更新父组件的状态,并通过他的子道具传递它:

当它从商店收到事件时,它首先通过商店的公共getter方法请求它所需的新数据.然后它调用自己的setState()或forceUpdate()方法,使其render()方法和所有后代的render()方法运行.

我们经常将商店的整个状态传递到单个对象中的视图链中,允许不同的后代使用他们需要的东西.除了将类似控制器的行为保持在层次结构的顶部,从而使我们的后代视图尽可能保持功能纯净之外,在单个对象中传递商店的整个状态也具有减少道具数量的效果我们需要管理.

(facebook flux docs - 概述)


Spo*_*ike 5

将商店数据放入组件的状态更有意义,这是因为道具可能会被父组件改变componentWillReceiveProps.因此,更新时间是有意义的state:

  • 商店的变更事件被解雇了
  • 每当道具改变时(将衍生数据仅与组件本身相关联的状态)

下面是一个示例组件,它可以更新侦听回流存储以及更改道具更改.我很少this.propsrender函数中使用,而是修改它们(创建仅在组件本身内使用的衍生数据),因为新的道具进来.我经常遇到这种模式,所以不妨写下来:

var SampleComponent = React.createClass({
    mixins: [Reflux.ListenerMixin],

    // reusable helper function to build state object
    buildStateFromProps: function(props) {
        return {
            actualHeight: props.height + 20
        }
    },

    // default props if no such was set by a parent component
    getDefaultProps: function() {
        return {
            height: 100
        };
    },

    // initial state with all value set to something default
    // even using buildStateFromProps with default props
    getInitialState: function() {
        // this.props is built before this.state
        var state = buildStateFromProps(this.props);
        // append default data from store
        state.text = '';
    },

    // happens when the parent component send different 
    // props data
    componentWillReceiveProps: function(nextProps) {
        // building derivative data from new props
        // reusing buildStateFromProps
        this.setState(buildStateFromProps(nextProps));
    },

    // setting up store to be used by the component
    componentDidMount: function() {
        // this.listenTo is a helper function ListenerMixin
        this.listenTo(sampleStore, sampleUpdated);
    },

    // is called from the sampleStore update
    sampleUpdated: function(sampleData) {
        this.setState({
            text: sampleData.text
        });
    },

    render: function() {
        return (
            // ... 
            // using this.state.text from store updates and
            // this.state.height from prop updates
        );
    }
});
Run Code Online (Sandbox Code Playgroud)

我将道具数据发送到状态的原因是为了避免使渲染功能混乱.否则,渲染函数将包含许多与"渲染"组件无关的代码.此外,如果此衍生数据用于应用程序的其他部分,则很容易将其从组件中拉出并将其放入存储中.

希望这可以帮助.