这可能是在回答问题和固执己见之间的那条线,但我会来回顾如何构建ReactJS组件,因为复杂性增加并且可以使用某些方向.
来自AngularJS,我希望将我的模型作为属性传递给组件,并让组件直接修改模型.或者我应该将模型拆分为各种state
属性,并在向上游发送时将其重新编译回来?什么是ReactJS方式?
以博客文章编辑器为例.试图直接修改模型最终看起来像:
var PostEditor = React.createClass({
updateText: function(e) {
var text = e.target.value;
this.props.post.text = text;
this.forceUpdate();
},
render: function() {
return (
<input value={this.props.post.text} onChange={this.updateText}/>
<button onClick={this.props.post.save}/>Save</button>
);
}
});
Run Code Online (Sandbox Code Playgroud)
这似乎不对.
是否更多是React方法来创建我们的text
模型属性state
,并在保存之前将其编译回模型:
var PostEditor = React.createClass({
getInitialState: function() {
return {
text: ""
};
},
componentWillMount: function() {
this.setState({
text: this.props.post.text
});
},
updateText: function(e) {
this.setState({
text: e.target.value
});
},
savePost: function() {
this.props.post.text = this.state.text;
this.props.post.save();
},
render: function() {
return (
<input value={this.state.text} onChange={this.updateText}/>
<button onClick={this.savePost}/>Save</button>
);
}
});
Run Code Online (Sandbox Code Playgroud)
这不需要调用this.forceUpdate()
,但随着模型的增长,(帖子可能有作者,主题,标签,评论,评级等......)组件开始变得非常复杂.
是第一种使用ReactLink的方法吗?
jxg*_*jxg 64
你的第二种方法更像是它.React并不关心模型,因为它关心的是价值以及它们如何在您的应用中流动.理想情况下,您的帖子模型将存储在根目录中的单个组件中.然后创建子组件,每个组件都使用模型的一部分.
您可以将回调传递给需要修改数据的子项,并从子组件中调用它们.
直接修改this.props或this.state不是一个好主意,因为React将无法接收更改.那是因为React对你的后道具进行浅层比较,以确定它是否已经改变.
我做了这个jsfiddle来展示数据如何从外部组件流向内部组件:
http://jsfiddle.net/jxg/M3CLB/
该handleClick
方法显示了3种(im)正确更新状态的方法:
var Outer = React.createClass({
getInitialState: function() {
return {data: {value: 'at first, it works'}};
},
handleClick: function () {
// 1. This doesn't work, render is not triggered.
// Never set state directly because the updated values
// can still be read, which can lead to unexpected behavior.
this.state.data.value = 'but React will never know!';
// 2. This works, because we use setState
var newData = {value: 'it works 2'};
this.setState({data: newData});
// 3. Alternatively you can use React's immutability helpers
// to update more complex models.
// Read more: http://facebook.github.io/react/docs/update.html
var newState = React.addons.update(this.state, {
data: {value: {$set: 'it works'}}
});
this.setState(newState);
},
render: function() {
return <Inner data={this.state.data} handleClick={this.handleClick} />;
}
});
Run Code Online (Sandbox Code Playgroud)
Fiz*_*han 35
来自React doc
props是不可变的:它们从父级传递,并由父级"拥有".为了实现交互,我们向组件引入了可变状态.this.state是组件的私有,可以通过调用this.setState()来更改.更新状态后,组件将重新呈现自身.
从TrySpace:当更新props(或state)时(通过setProps/setState或parent),组件也会重新渲染.
Jim*_*ien 13
我不确定我是否回答了你的问题,但我发现,特别是在大型/不断发展的应用程序中,容器/组件模式运行得非常好.
基本上你有两个React组件:
注意这个例子可能过于简单,无法说明这种模式的好处,因为对于这种简单的案例来说,它非常冗长.
/**
* Container Component
*
* - Manages component state
* - Does plumbing of data fetching/saving
*/
var PostEditorContainer = React.createClass({
getInitialState: function() {
return {
text: ""
};
},
componentWillMount: function() {
this.setState({
text: getPostText()
});
},
updateText: function(text) {
this.setState({
text: text
});
},
savePost: function() {
savePostText(this.state.text);
},
render: function() {
return (
<PostEditor
text={this.state.text}
onChange={this.updateText.bind(this)}
onSave={this.savePost.bind(this)}
/>
);
}
});
/**
* Pure Display Component
*
* - Calculates styling based on passed properties
* - Often just a render method
* - Uses methods passed in from container to announce changes
*/
var PostEditor = React.createClass({
render: function() {
return (
<div>
<input type="text" value={this.props.text} onChange={this.props.onChange} />
<button type="button" onClick={this.props.onSave} />
</div>
);
}
});
Run Code Online (Sandbox Code Playgroud)
通过将显示逻辑和数据/状态管理分开,您有一个可重复使用的显示组件:
您还有一个处理所有外部通信的容器组件.如果您稍后对*进行任何重大更改,这将使您更容易灵活地访问数据.
这种模式也使编写和实现单元测试变得更加直接.
迭代了几次大型React应用程序,我发现这种模式可以让事情变得相对轻松,特别是当你有更大的组件具有计算样式或复杂的DOM交互时.
*阅读通量模式,看看Marty.js,这很大程度上激发了这个答案(我最近一直在使用很多) Redux(和react-redux),它非常好地实现了这种模式.
请注意2018年或之后阅读此内容的人:
自从这个答案写完以来,React已经发展了很多,尤其是在引入Hooks之后.但是,此示例中的基础状态管理逻辑保持不变,更重要的是,保持状态和表示逻辑分离所带来的好处仍然以相同的方式应用.
归档时间: |
|
查看次数: |
48831 次 |
最近记录: |