React 因为他的性能而著名因为他有一个虚拟 DOM 层并且只有在需要时才更新真实 DOM 即使是同样地信息这也比一直直接更新 DOM 要快很多但是, React 的智能仅此而已(目前为止), 我们的任务是知道 React 的预期行为以及限制, 这样我们才不会意外损失性能
我们需要关注的一方面是 React 如何决定什么时候重新渲染组件不是重新渲染 DOM 节点, 只是调用 render 方法来改变虚拟 DOM 我们可以通过告诉 React 什么时候需要渲染什么时候不需要渲染来帮助 React 让我们依次来看看这些
1. 组件的状态发生改变
只有在组件的 state 变化时才会出发组件的重新渲染状态的改变可以因为 props 的改变, 或者直接通过 setState 方法改变组件获得新的状态然后 React 决定是否应该重新渲染组件不幸的是, React 难以置信简单地将默认行为设计为每次都重新渲染
组件改变? 重新渲染父组件改变? 重新渲染一部分没有导致视图改变的 props 改变? 重新渲染
- class Todo extends React.Component {
- componentDidMount() {
- setInterval(() = >{
- this.setState(() = >{
- console.log('setting state');
- return {
- unseen: "does not display"
- }
- });
- },
- 1000);
- }
- render() {
- console.log('render called');
- return (...);
- }
- }
在这个 (非常刻意的) 例子中, Todo 将会每秒重新渲染依次, 即使 render 方法根本没有使用 unseen 事实上, unseen 值甚至都不改变你可以在 CodePen
里查看这个例子的实际版本
好吧, 但是每次都重新渲染没有什么帮助
我的意思是, 我非常感谢 React 的细心谨慎如果状态改变但是组件没有正确渲染的话更糟权衡之下, 每次都重新渲染绝对是一个安全的选择
但是重新渲染的时间成本看起来非常昂贵(例子里非常夸张地表现了出来)
是的, 在不必要的时候重新渲染会浪费循环并且不是一个好的想好但是, React 不能知道什么时候可以安全的跳过重新渲染, 所以 React 无论是否重要每次都重新渲染
我们如何告诉 React 跳过重新渲染?
那就是第二点要说的内容
2. shouldComponentUpdate 方法
shouldComponentUpdate 方法默认返回 true, 这就是导致每次更新都重新渲染的原因但是你可以在需要优化性能时重写这个方法来让 React 更智能比起让 React 每次都重新渲染, 你可以告诉 React 你什么时候不像触发重新渲染
当 React 将要渲染组件时他会执行 shouldComponentUpdate 方法来看它是否返回 true(组件应该更新, 也就是重新渲染)所以你需要重写 shouldComponentUpdate 方法让它根据情况返回 true 或者 false 来告诉 React 什么时候重新渲染什么时候跳过重新渲染
当你使用 shouldComponentUpdate 方法你需要考虑哪些数据对与重新渲染重要让我们回到这个例子
正如你所看到的, 我们只想在 title 和 done 属性改变的时候重新渲染 Todo 我们不关心 unseen 是否改变, 所以我没有把它包含在 shouldComponentUpdate 方法中
当 React 渲染 Todo 组件 (通过 setState 触发) 他会首先检查状态是否改变 (通过 props 和 state) 假设状态改变了(因为我们显式地调用了 setState 所以这会发生)React 会检查 Todo 的 shouldComponentUpdate 方法 React 会根据 shouldComponentUpdate 方法返回值为 true 或者 false 来决定从哪里渲染
更新后的代码仍然会每秒调用一次 setState 但是 render 只有在第一次加载时 (或者 title 或 done 属性改变后) 才会调用你可以在这里看到
看起来有很多工作去做
是的, 这个例子非常冗长因为有两个属性 (title 和 done) 需要关注并且只有一个可以忽略 (unseen) 根据你的数据可能仅检查一个或两个属性并且忽略其他会更有意义
重要提示
当子组件的的 state 变化时, 返回 false 并不能阻止它们重渲染
Facebook 的 React 文档
这作用于子组件的状态而不是他们的 props 所以如果一个子组件内部管理了一些他自己的状态(使用他自己的 setState), 这仍然会更新但是如果父组件的 shouldComponentUpdate 方法返回了 false 就不会传递更新后的 props 给他的子组件, 所以子组件不会重渲染, 即使他们的 props 变化了
额外内容: 简单性能测试
编写并且在 shouldComponentUpdate 方法中运行计算的时间成本可能会很昂贵, 所以你需要确保值得做在写 shouldComponentUpdate 方法前你可以测试 React 一个周期默认会消耗多少时间有了这个信息做参考, 在做性能优化时你可以做一个不盲目的决定
使用 React 的性能工具去发现浪费的周期:
- Perf.start()
- // Do the render
- Perf.stop()
- Perf.printWasted()
哪一个组件浪费了很多渲染周期? 你怎么通过 shouldComponentUpdate 方法让他们更智能? 试着使用性能测试工具来比较他们的性能
来源: http://www.jqhtml.com/11116.html