如果flux存储是一个维护数据状态的单例,为什么组件在访问存储时使用setState而不是setProps?这不仅仅意味着我开始在两个(或更多)位置保存应用程序状态吗?
Flux / React文档和示例似乎都指向setState作为首选解决方案,但我与一些同事在工作中进行了一次有趣的对话,并想知道是否有其他人遇到过这个
编辑: 你可以在这个网址中看到我在说什么: https://github.com/facebook/flux/blob/master/examples/flux-chat/js/components/ThreadSection.react.js
注意ThreadSection是一个子组件,它直接从商店获取数据并将其用作状态。
如果你遵循React“方式”我会期望状态由商店管理 - 而不是子组件。
我们想到的解决方案是获取顶级组件中的所有商店(作为道具),并根据需要将它们传递给子组件。但这很快就变得相当难看。
我们这样做是因为setProps不适用于子组件
答案 0 :(得分:43)
了解您应该有两种组件。有状态组件和视图组件。
有状态组件可以有3种状态:初始状态,用户输入状态和数据存储状态。
有状态组件就像"小部件"中的小入口点。你正在组装。对于下游依赖或数据注入,不再有单个应用程序范围的入口点,因为所有这些窗口小部件都有自己独立的生命周期。这就是为什么他们自己需要访问&听商店。
除了行为属性之外,有状态组件不会通过上游属性接收实际数据。
有状态组件管理自己的状态并将其传递给子级以通过下游属性进行渲染。
有状态组件通常不直接呈现html DOM元素。它们更像MVC中的控制器,并使用其他dumber组件(如MVC中的视图)来实际呈现DOM元素。
Dumber组件与视图类似,因此它们只包含呈现DOM元素的逻辑。将它们视为handlebars.js模板,只接收属性,并简单地将它们呈现为DOM元素,可能带有循环等。它们是无状态渲染器。
希望这能回答你的问题。
答案 1 :(得分:7)
根据正式文档,商店应该更新父组件的状态,并通过他的子道具传递下来:
当它从商店收到事件时,它首先通过商店的公共getter方法请求所需的新数据。然后它调用自己的setState()或forceUpdate()方法,使其render()方法和所有后代的render()方法运行。
我们经常将商店的整个状态传递到单个对象中的视图链中,允许不同的后代使用他们需要的东西。除了将类似控制器的行为保持在层次结构的顶部,从而使我们的后代视图尽可能保持功能纯净之外,在单个对象中传递商店的整个状态也具有减少道具数量的效果我们需要管理。
答案 2 :(得分:5)
将商店数据放入组件的状态更有意义,这是因为道具可能会被componentWillReceiveProps
的父组件更改。因此,有时候更新state
:
下面是一个示例组件,用于更新对reflux store的监听以及对道具更改的更新。我很少在this.props
函数中使用render
,而是修改它们(创建仅在组件本身内使用的衍生数据),因为新的道具进入。我不断遇到这种模式所以不妨写下来:
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
);
}
});
我将道具数据发送到状态的原因是为了避免使渲染功能混乱。否则,渲染函数将包含许多与“渲染”组件无关的代码。此外,如果此衍生数据用于应用程序的其他部分,则可以轻松地将其从组件中拉出并将其放入商店。
希望这有帮助。
答案 3 :(得分:1)
这个问题的有效答案隐藏在对先前答案的评论中:
@idolize你也可以使用React上下文传递商店(隐藏的, 尚未正式记录的功能)。它非常好,因为你 不必做所有传递层次结构的事情。有几个 关于上下文的文章,在线搜索! - Andy Jul 17&15; 15 at 18时41分