《React——引领未来的用户界面开发框架》总结

所有代码示例:http://git.io/vlcpa

4 数据流

PropTypes

提供了一种验证 props 的方式

State

千万不能直接修改 this.state,永远记得要通过 this.setState 方法修改

state 中应只保存最简单的数据,不要保存计算出的值

不要尝试把 props 复制到 state 中,要尽可能将 props 当作数据源

当不需要内部状态、refs 和生命周期函数时,将组件变成函数组件可以减少冗余和复杂性

8 DOM 操作

ReactDOM.findDOMNode

1
2
import ReactDOM from 'react-dom';
ReactDOM.findDOMNode(ReactComponent);

在 componentDidMount 执行后,才能用

this.refs.xxx

可用性

把要求传达清楚

placeholder 尽量简短,不要有验证提示,验证提示在输入框外面

不断地反馈

用户有时候会没有耐心,但是如果告诉他们程序正在处理他们的请求,他们就会变得耐心。所以要有一些诸如 加载中、进度条、信息提示等进行反馈

迅速响应

过渡动画过长,会让用户产生挫败感。

eg:当用户点击“喜欢”的时候,可以在给服务器发送 AJAX 之前先增加喜欢数。如果 AJAX 调用要花费太长时间,这种方式会让用户感觉不到延迟。不过这种方式在错误处理方面会产生一些问题。

符合用户的预期

用户对事物如何工作有自己的预期,这种预期基于他们之前的经验,而不是来自于你的应用。

如果你的应用长得像用户所在的平台,那么要尽量遵循平台的默认行为。另一种方式是从根本上改变你的用户界面,这样你的应用就不用模仿其他平台了。

可访问

视力受损

减少用户的输入

自动填充等

10 动画

ReactCSSTransitionGroup

requestAnimationFrame 间隔渲染

react-motion

spring animation

11 性能优化

shouldComponentUpdate

方法会返回一个布尔值,如果返回 false 就是不要调用组件的渲染方法,并使用之前渲染好的虚拟 DOM,如果返回 true 则调用组件的渲染方法并计算出新的虚拟 DOM。(默认返回 true,因此组件总是会调用 render 方法)

对于给定同样 props 和 state 总是渲染出同样结果的组件,可以用 react-addons-pure-render-mixin 插件来处理 shouldComponentUpdate

使用 react-mixin 来提供 mixin 的支持,这也是为数不多应该使用 mixin 而不是高阶组件的地方

key

如果一个组件的 key 属性发生变化,那么 react 就会跳过 DOM diff,同时完全弃置 div 所有的子元素,并重新从头开始渲染。

在渲染大型子树避免 diff 运算时,这样做很有用

1
2
3
4
var items = sortBy(this.state.sortingAlgorithm, this.props.items);
return items.map(function (item) {
return <img src={item.src} />;
});

如果顺序改变,react 会对元素进行 diff 操作并确定最高效的操作时改变其中几个 img 元素的 src,这样可能会导致浏览器查询缓存,甚至会导致新的网络请求。

1
return <img src={item.src} key={item.id} />;

这样 react 得出的结论就不是改变 src 的属性,而是使用 insertBefore 操作,而这个操作是移动 DOM 节点最高效的方式。

单一级别约束对于指定的父组件,每个子组件的 key 必须是独一无二的。这同时也意味着从一个父组件移动到另一个父组件的情况是不会被处理的。

尽管 key 看似作为一个属性被传入了,但是其实在组件的任何位置都无法实际获取到它

12 服务端渲染

  • seo
  • 提升性能:因为在加载 js 脚本的时候,浏览器就可以进行页面渲染

虚拟 DOM 作为内存中的 DOM 表现,为 React 再 Node.js 这类非浏览器环境下的运行提供了可能。

React 可以从虚拟 DOM 中生成一个字符串,而不是更新真正的 DOM。这使得我们可以在客户端和服务端使用同一个 React 组件。

React 提供了两个可用于服务端渲染组件的函数:React.renderToString 和 React.renderToStaticMarkup

渲染函数

服务端不存在 DOM,所以不能使用 React.render 方法

React.renderToString

是一个快速的同步函数

React.renderToStaticMarkup

除了不会包含 React 的 data 属性外,和 React.renderToString 没有区别

当且仅当不打算在客户端渲染这个组件时才用:

React 可以重用服务端提供的 DOM,所以它可以跳过生成 DOM 节点以及把它们挂载到文档中这两个昂贵的进程。

渲染客户端的时候,如果 data-react-checksum 不匹配,React 会舍弃服务端提供的 DOM,然后生成新的 DOM 节点,并更新到文档中。此时,React 不再拥有服务器渲染带来的各种性能上的优势。

服务端组件生命周期

没有 componentDidMount 和 componentWillUnmount,只有 componentWillMount 在 client 和 server 渲染都有效。

在 componentWillMount 内注册的所有事件监听器及定时器都有可能潜在地导致服务器内存泄漏。最佳做法是只在 componentDidMount 内部创建事件监听器和定时器,然后在 componentWillUnmount 内清除这两者。

设计组件

  • 务必慎重考虑如何将组件的 state 传递到客户端
  • 在设计组件时,需要保证将同一个 props 传递到组件中时,总会输出相同的初始渲染结果

异步状态

问题:因为 React.renderToString 是同步的,所以没办法使用组件的任何一个生命周期方法来抓取异步的数据。

解决方案:使用 statics 函数来抓取异步数据,然后把数据传递到组件中用于渲染。将 initialState 作为 props 值传递到客户端。使用组件生命周期方法来监听变化,然后使用同一个 statics 函数更新状态。

同构路由

为了在服务端渲染出拥有路由的 React 应用,必须确保路由系统支持无 DOM 渲染。

抓取异步数据是路由系统及其控制器的职责。

单例、实例及上下文

在服务端运行代码时,可能存在同一个应用的多个实例在相同作用域内同时运行的情况,就有可能出现两个实例都去更改单例状态的情况,这会导致异常的行为发生。

Contextify 之类的包准许你在服务端彼此隔离地运行代码。一旦加载完代码,你就可以调用环境中的所有函数。这种方法可以让你随意地使用单例模式,而不用考虑性能上的花销,因为每次请求都对应一个全新的 Node.js V8 实例。

React 不鼓励在组件树中传递上下文和实例。这种做法会降低组件的可移植性,并且应用内组件依赖的更改会对层级上的所有组件产生联动式影响。

13 开发工具

webpack

当你移除某个组件的时候,他的所有依赖也会自动被移除。这意味着不会再有未被使用的 CSS 或者图片遗留在代码目录中

多个 loader 通过!连接:

1
2
3
4
{
test:/\.(css)$/,
loader:'style-loader!css-loader'
}

14 测试

测试驱动开发(TDD)

边写代码边测试,就自然而然地被要求遵守单一职责原则迪米特法则,并保持代码的模块化。

自动化测试:单元测试,集成测试,功能测试,性能测试,安全测试 以及 视觉测试

16 不可变性

性能优势

如果有 shouldComponentUpdate,只需要检查 porps 中的一个字段,就可以返回 true 或者 false。但是如果需要检查很多字段,有的字段还包含对象,性能就会降低。所以,判断两个可变对象的值是否相等就是问题的关键所在。

这时,如果使用不可变的 state 和 props,就只需简单地比较 oldProps!==newProps 就可以了。(当使用不可变对象来表示 props 时,为了得到全新的 props,无法直接在当前的 props 修改,必须实例化新的不可变对象替代它)

性能消耗

可变对象改起来容易但不便做比较,反过来,不可变对象比较起来很快,但是更新就比较慢了。

不可变类库不能再当前对象上进行变更,最少必须实例化一个新对象,修改它使之与原对象完全一致(除了改变了的这个字段不一样)。不单单更新过程需要花费时间,垃圾回收也需要,毕竟多余的对象必须被回收。权衡起来,对于大多数 React 应用还是值得的。别忘了简单的更新函数通常会调用大量的渲染函数,这些渲染函数在构造返回值的过程中需要实例化很多对象。牺牲一点更新的速度,以换取大量的渲染函数执行的损耗,这从性能的角度上来说是有优势的。

除了性能,还要付出的一点代价就是无法使用 setState 和 setProp 这两个函数,只能用 replaceState 和 replaceProps 了

架构优势

当把可变数据从一个函数传递到另外一个函数的时候,如果期望函数执行完后,数据不会被修改,通常要提前克隆要传递的数据,传递克隆对象。但是并没有不可变数据高效,不可修改的数据可以获得更快的克隆速度。借助贯穿始终的不可变数据将获得一致的可安全传递特性。

使用 Immutability Helpers Addon

使用 seamless-immutable

使用 Immutable.js

immutable-js

Immutable.Map

Immutable.Vector

17 其他使用场景

桌面应用

electronjs

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2018-2020 Jee
  • Visitors: | Views:

如果您觉得此文章帮助到了您,请作者喝杯咖啡吧~

支付宝
微信