1、渲染篇

1.1 缓存React.element对象

这是一种父对子的渲染控制方案,来源于一种情况,父组件重新 render ,子组件有没有必要跟着父组件一起 render。

  1. /* 子组件 */
  2. function Children ({ number }){
  3. console.log('子组件渲染')
  4. return <div>let us learn React! { number } </div>
  5. }
  6. /* 父组件 */
  7. export default class Index extends React.Component{
  8. state={
  9. numberA:0,
  10. numberB:0,
  11. }
  12. render(){
  13. return <div>
  14. <Children number={ this.state.numberA } />
  15. <button onClick={ ()=> this.setState({ numberA:this.state.numberA + 1 }) } >改变numberA -{ this.state.numberA } </button>
  16. <button onClick={ ()=> this.setState({ numberB:this.state.numberB + 1 }) } >改变numberB -{ this.state.numberB }</button>
  17. </div>
  18. }
  19. }

优化:当numberA值变化才会重新渲染children组件

  1. export default function Index(){
  2. const [ numberA , setNumberA ] = React.useState(0)
  3. const [ numberB , setNumberB ] = React.useState(0)
  4. return <div>
  5. { useMemo(()=> <Children number={numberA} />,[ numberA ]) }
  6. <button onClick={ ()=> setNumberA(numberA + 1) } >改变numberA</button>
  7. <button onClick={ ()=> setNumberB(numberB + 1) } >改变numberB</button>
  8. </div>
  9. }

1.2 PureComponent

浅比较 state 和 props 是否相等;

1.3 shouldComponentUpdate

shouldComponentUpdate 可以根据传入的新的 props 和 state ,或者 newContext 来确定是否更新组件。

1.4 React.memo

React.memo 可作为一种容器化的控制渲染方案,可以对比 props 变化,来决定是否渲染组件。

React.memo 接受两个参数,第一个参数 Component 原始组件本身,第二个参数 compare 是一个函数,可以根据一次更新中 props 是否相同决定原始组件是否重新渲染。

1.5 打破渲染限制

类组件更新如果调用的是 forceUpdate 而不是 setState ,会跳过 PureComponent 的浅比较和 shouldComponentUpdate 自定义比较。

1.6 什么时候需要注意渲染节流

  • 第一种情况数据可视化的模块组件(展示了大量的数据),这种情况比较小心因为一次更新,可能伴随大量的 diff ,数据量越大也就越浪费性能,所以对于数据展示模块组件,有必要采取 memo , shouldComponentUpdate 等方案控制自身组件渲染。
  • 第二种情况含有大量表单的页面,React 一般会采用受控组件的模式去管理表单数据层,表单数据层完全托管于 props 或是 state ,而用户操作表单往往是频繁的,需要频繁改变数据层,所以很有可能让整个页面组件高频率 render 。
  • 第三种情况就是越是靠近 app root 根组件越值得注意,根组件渲染会波及到整个组件树重新 render ,子组件 render ,一是浪费性能,二是可能执行 useEffect ,componentWillReceiveProps 等钩子,造成意想不到的情况发生。

1.7 开发中的细节

  • 开发过程中对于大量数据展示的模块,开发者有必要用 shouldComponentUpdate ,PureComponent来优化性能。
  • 对于表单控件,最好办法单独抽离组件,独自管理自己的数据层,这样可以让 state 改变,波及的范围更小。
  • 如果需要更精致化渲染,可以配合 immutable.js 。
  • 组件颗粒化,配合 memo 等 api ,可以制定私有化的渲染空间。

1.8 问与答

1.8.1 问:详细介绍一下 useMemo ?

useMemo 用法:const cacheSomething = useMemo(create,deps)

  • create:第一个参数为一个函数,函数的返回值作为缓存值。
  • deps: 第二个参数为一个数组,存放当前 useMemo 的依赖项,在函数组件下一次执行的时候,会对比 deps 依赖项里面的状态,是否有改变,如果有改变重新执行 create ,得到新的缓存值。
  • cacheSomething:返回值,执行 create 的返回值。如果 deps 中有依赖项改变,返回的重新执行 create 产生的值,否则取上一次缓存值。

useMemo原理:
useMemo 会记录上一次执行 create 的返回值,并把它绑定在函数组件对应的 fiber 对象上,只要组件不销毁,缓存值就一直存在,但是 deps 中如果有一项改变,就会重新执行 create ,返回值作为新的值记录到 fiber 对象上。

useMemo应用场景:

  • 可以缓存 element 对象,从而达到按条件渲染组件,优化性能的作用。
  • 如果组件中不期望每次 render 都重新计算一些值,可以利用 useMemo 把它缓存起来。
  • 可以把函数和属性缓存起来,作为 PureComponent 的绑定方法,或者配合其他Hooks一起使用。

1.8.2 问:useMemo和useCallBack的区别 ?

答:useCallback 第一个参数就是缓存的内容,useMemo 需要执行第一个函数,返回值为缓存的内容,比起 useCallback , useMemo 更像是缓存了一段逻辑,或者说执行这段逻辑获取的结果。那么对于缓存 element 用 useCallback 可以吗,答案是当然可以了。