前言
React框架让开发者创建UI组件变得很容易,开发者可以很快实现声明式、响应式编程模型,而且将DOM操作抽象化后仍然不会消耗性能。
如果你已经习惯使用jQuery创建web应用,手动操作DOM,以下五点建议也许可以帮助你如果按照React的方式来思考如何实现组件。
建议1:UI应该是引入数据的函数
在典型的jQuery应用中,业务逻辑和UI管理代码经常混合在一起,导致代码很难理解,bug很难修复。
React应用中,你应该通过优先思考如何设计数据来考虑UI实现。
这块UI需要什么数据?
我如何转换这份数据到DOM组件中?
类似这些问题的答案将会成为思考的结果。
基于以上数据,react组件应该总是返回相同的结果,让react组件很容易理解和测试。
因此,当你反问自己, 我如何更新我的UI? 真正应该问的是,我应该改变哪些数据来完成数据到DOM转换过程,最后输出正确的结果?
建议2:不要操作DOM
这点和上面的紧密相关。
React将真实的DOM操作抽象为虚拟DOM, 虚拟DOM就是一系列代表真实DOM如何展示的数据结构。
基于这个原因,你不应该手动操作DOM。相反,直接使用React声明式编程模型决定渲染内容,让React来处理DOM操作。
下面是jQuery应用的简单示例, 你也许要跟踪布尔状态,根据状态值添加或删除类:
$myBtn = $('<button>');
$myBtn.addClass('button');
if(toggled) {
$myBtn.addClass('toggled');
}
$myBtn.appendTo(...);
$myBtn.toggleClass('toggled', toggled);
使用React, 你只需要简单跟踪组件的内部状态,告诉React的如何渲染:
render: function(){
var classes = 'button';
if(this.state.toggled) classes += " toggled";
return <button className={classes}>...</button>;
}
由于React是一个响应式UI库,当toggled状态改变时,React会根据renders输出重新计算DOM渲染,最后根据需要修改DOM。
React支持批量DOM更新,并且为了提升性能会做最小化的DOM操作。
如果你手动处理DOM, 你可能会破坏React处理,无法正确完成DOM变化。
当然,有时因为不能直接操作DOM, 你也不能实现一些特定功能。
React提供了方便的生命周期钩子函数,你可以声明钩子函数实现特定功能,并且不会破坏React渲染循环。但记住生命周期不是默认创建组件的方式!
建议3:转换数据流
创建大型React树组件十分容易,并且内部各自管理内部应用状态。
但是这里,决定哪些组件管理哪些状态会变得困难。
一个好方法就是尽可能在几个地方集中化数据存储和管理,特别是在组件继承的顶端设计数据,然后向通过属性向底层无状态组件传递数据。
如果这些组件也需要更改数据,可以传入函数应用,在组件内部调用来更新顶层数据。
这项设计有个好处,让无状态组件变得更轻,更容易理解、调试和测试。
大型应用中,数据集中技术或flux模式可以帮助更好管理数据,集中改变操作。
建议4:拥抱组合
编写大型React组件开始会很容易,只需要有点想法就可以开工。
一旦你这样做,将可以往回看,考虑将功能分解成更小的子组件。
另外,编写第一个组件之前思考组件设计。你会惊奇发现看下草稿后很容易明确应用的各个组件。
想下处理特定数据或展示逻辑的UI界面,或者频繁更新的部分。这些都可以成为独立的组件。
这些子组件还可以根据场景分解为更细的组件。
例如,我们看下下面的组件片段:
render: function() {
<div className="container">
<div className="login-logout">
<img src={getAvatarUrl(this.props.user)} />
Logged in as {this.props.user.username}.
<a href='#' onClick={this.logout}>Logout</a>
</div>
<div>
<h1>Your posts:</h1>
{this.props.posts.map(this.renderPost)}
</div>
<div>
<h2>Comments:</h2>
{this.props.comments.map(this.renderComment)}
</div>
</div>
}
你可以很容易拆成下面的组件:
render: function() {
return (
<div className="container">
<LoginLogoutBar user={this.props.user} logout={this.logout} />
<PostsList title="Your posts:" posts={this.props.posts} />
<CommentsList title="Comments:" comments={this.props.comments} />
</div>
);
}
上面的例子还可以继续拆分,例如, LoginLogoutBar会用到UserAvatar组件,渲染给定用户的头像。
创建一大堆更小,更具复用性的组件通常来源于一些复杂的大型组件、
这样拆分让你的应用更容易扩展,测试更容易,基于黑盒的考虑,会更容易理解。
建议5:注意可变数据
React拥有如此良好性能特性的原因之一就是React知道数据的变化时机,还能分辨出需要渲染的最小化界面UI集合。
但是由于React是js框架,这项工作不会简单。
React通过调用setState实现数据变化。
如果你不调用setState更新状态,你的组件不会更新渲染。
因此,明确可变数据会很重要。向某些函数传递对象,却不知道函数内部操作会直接改变对象,这些会导致未知的变化。
另外,当数据变化时,React会异步批量更新界面UI。所以手动变动数据实际会导致某些操作被React丢弃。
React提供不可变辅助工具帮助处理深层次子树或子数据组数据。
你也可以看看像Immutable.js这样的库来处理部分不可变数据结构。
译者注
-
因译者水平有限,如有错误,欢迎指正交流
网友评论