我已经读了几天关于React的文章。我可以理解我正在看的大部分内容,但我对自己的写作能力并不是完全有信心。我一直在开发一个小的web应用程序,它通过jQuery和互相添加元素来生成所有的html。我想尝试用React重新构建它,因为我相信它会更快。这个JSFiddle是我正在做的这类事情的一个小例子。你会怎么用React来写呢?
JS:
function remove() {
this.remove();
}
function timed_append_new_element() {
setTimeout(function () {
var added_content = $("<span />", {
class: "added_content",
text: "Click to close",
click: remove
});
container.append(added_content);
}, 3000);
}
function append_new_element() {
var added_content = $("<span />", {
class: "timed_added_content",
text: "Click to close",
click: remove
});
container.append(added_content);
}
var container = $("<div />", {
class: "container"
});
var header = $("<span />", {
class: "header",
text: "jQuery to React.js Header"
});
var add_button = $("<button />", {
class: "add_button",
text: "Add Element",
click: append_new_element
});
var timed_add_button = $("<button />", {
class: "add_button",
text: "Add Element in 3 seconds",
click: timed_append_new_element
});
container.append(header);
container.append(add_button);
container.append(timed_add_button);
$("body").append(container);
发布于 2014-05-11 23:27:51
有几个基本原则需要记住,它们可以帮助你构建一个好的React应用程序:
您的UI应该是data的一个函数
在许多"jQuery汤“风格的应用程序中,应用程序的业务逻辑、应用程序的数据和UI交互代码都混合在一起。这使得这类应用程序很难调试,尤其是难以扩展。与许多现代客户端应用程序框架一样,React强调UI只是数据的一种表示形式。如果您希望更改UI,则应该更改一段数据,并允许框架使用任何绑定系统来为您更新UI。
在React中,每个组件(理想情况下)都是两段数据的函数-传递给组件实例的属性和组件内部管理的状态。给定相同的属性(或"props")和状态,组件应该以相同的方式呈现。
这可能是一个抽象的想法,没有具体的例子,所以在我们继续下一步的时候请记住这一点。
请勿接触DOM
与其他数据绑定框架相比,在React中,如果可能的话,您应该尽量不直接操作DOM。React的许多性能和复杂性特征之所以成为可能,是因为React在内部使用了一个带有差分算法的虚拟DOM来操作真实的DOM。每当您构建一个组件并执行自己的DOM操作时,您都应该问问自己,是否可以使用React的虚拟DOM特性更地道地构建相同的特性。
当然,有时您需要访问DOM,或者您可能希望合并一些jQuery插件而不在React中重新构建它。在这种情况下,React为您提供了良好的component lifecycle hooks,您可以使用它来确保React的性能不会受到太大影响(或者,在某些情况下,为了防止组件完全崩溃)。
不操纵DOM与上面的"UI作为数据的函数“密切相关。
颠倒数据流
在大型React应用程序中,可能很难跟踪哪个子组件正在管理某个应用程序数据。出于这个原因,React团队建议将数据操作逻辑放在一个中心位置。要做到这一点,最直接的方法是将回调传递给子组件;Facebook还开发了一个名为Flux的体系结构,该体系结构具有its own website。
创建可组合组件
很多时候,编写一个管理多个状态或多个UI逻辑的大型组件是很有诱惑力的。在可能的情况下(并且在合理的范围内),您应该考虑将较大的组件拆分成对单个数据或UI逻辑进行操作的较小组件。这使得扩展和移动应用程序的各个部分变得更加容易。
注意可变数据
由于组件状态只能通过从组件内部调用this.setState
来更新,因此提防可变数据是很有帮助的。当有多个功能(或组件!)时更是如此可能会在同一时间内更新可变对象;React可能会尝试批量处理状态更改,而您可能会丢失更新!正如Eliseu Monar的评论中所提到的,在对可变对象进行变异之前,请考虑克隆它们。React有immutability helpers可以提供帮助。
另一种选择是完全放弃直接保持可变数据结构的状态;上面提到的Flux模式是对这种想法的一种有趣的采用。
React网站上有一篇很棒的文章,名为Thinking in React,它介绍了如何将一个想法或模型转化为React应用程序,我强烈建议您阅读这篇文章。作为一个具体的例子,让我们看一下您提供的代码。实际上,您只需要管理一段数据:存在于container
元素中的内容列表。对UI的所有更改都可以通过对该数据的添加、删除和更改来表示。
通过应用上面的原则,您的最终应用程序可能如下所示:
/** @jsx React.DOM */
var Application = React.createClass({
getInitialState: function() {
return {
content: []
};
},
render: function() {
return (
<div className="container">
<span className="header">jQuery to React.js Header</span>
<button className="add_button"
onClick={this.addContent}>Add Element</button>
<button className="add_button"
onClick={this.timedAddContent}>Add Element in 3 Seconds</button>
{this.state.content.map(function(content) {
return <ContentItem content={content} removeItem={this.removeItem} />;
}.bind(this))}
</div>
);
},
addContent: function() {
var newItem = {className: "added_content", text: "Click to close"},
content = this.state.content,
newContent = React.addons.update(content, {$push: [newItem]});
this.setState({content: newContent});
},
timedAddContent: function() {
setTimeout(function() {
var newItem = {className: "timed_added_content", text: "Click to close"},
content = this.state.content,
newContent = React.addons.update(content, {$push: [newItem]});
this.setState({content: newContent});
}.bind(this), 3000);
},
removeItem: function(item) {
var content = this.state.content,
index = content.indexOf(item);
if (index > -1) {
var newContent = React.addons.update(content, {$splice: [[index, 1]]});
this.setState({content: newContent});
}
}
});
var ContentItem = React.createClass({
propTypes: {
content: React.PropTypes.object.isRequired,
removeItem: React.PropTypes.func.isRequired
},
render: function() {
return <span className={this.props.content.className}
onClick={this.onRemove}>{this.props.content.text}</span>;
},
onRemove: function() {
this.props.removeItem(this.props.content);
}
});
React.renderComponent(<Application />, document.body);
您可以在this JSFiddle中查看实际运行的代码:http://jsfiddle.net/BinaryMuse/D59yP/
该应用程序由两个组件组成:一个名为Application
的顶级组件(在其状态下)管理一个名为content
的数组,以及一个名为ContentItem
的组件,它表示该数组中单个项的UI和行为。Application
的render
方法为内容数组中的每一项返回一个ContentItem
元素。
需要注意的是,管理content
数组中的值的所有逻辑都是在Application
组件中处理的;ContentItem
组件被传递了一个对Application
的removeItem
方法的引用,当单击该方法时,ContentItem
将委托该方法。这将所有用于操作状态的逻辑都保留在顶级组件中。
https://stackoverflow.com/questions/23585765
复制相似问题