React组件的渲染和更新流程

138 阅读2分钟

React的渲染流程

image.png

React的渲染流程

  • 在render函数中返回jsx, jsx会创建出ReactElement对象(通过React.createElement的函数创建出来的)
  • ReactElement最终会形成一棵树结构, 这棵树结构就是vDOM
  • React会根据这样的vDOM渲染出真实DOM

React的更新流程

image.png

React更新流程

  • props/state发生改变
  • render函数重新执行
  • 产生新的DOM树结构
  • 新旧DOM树 进行diff算法
  • 计算出差异进行更新
  • 最后更新到真实DOM

什么是diff算法? diff算法并非React独家首创,但是React针对diff算法做了自己的优化,使得时间复杂度优化成了O(n) 对比两颗树结构,然后帮助我们计算出vDOM中真正变化的部分,并只针对该部分进行实际的DOM操作,而非渲染整个页面,从而保证了每次操作后页面的高效渲染。

  • React在props或state发生改变时,会调用React的render方法,会创建一颗不同的树

  • React需要基于这两颗不同的树之间的差别来判断如何有效的更新UI

  • 如果一棵树参考另外一棵树进行完全比较更新,那么即使是最先进的算法,该算法的复杂程度为 O(n³) ,其中 n 是树中元素的数量

  • 如果在 React 中使用了该算法,那么展示 1000 个元素所需要执行的计算量将在十亿的量级范围

  • 这个开销太过昂贵了,于是,React对这个算法进行了优化,将其优化成了O(n)

    • 同层节点之间相互比较,不会跨节点比较(一旦某个节点不同,那么包括其后代节点都会被替换)

    • 不同类型的节点,产生不同的树结构(当根节点为不同类型的元素时,React 会拆卸原有的树并且建立起新的树)

    • 开发中,可以通过key属性标识哪些子元素在不同的渲染中可能是不变的

  • 在遍历列表时,总是会提示一个警告,让我们加入一个key属性,当子元素拥有 key 时,React 使用 key 来匹配原有树上的子元素以及最新树上的子元素。

    • 在最后位置插入数据 -- 这种情况,有无key意义并不大
    • 在前面插入数据 -- 这种做法,在没有key的情况下,所有的li都需要进行修改
    • 在中间插入元素 -- 新增2014, key为2016元素仅仅进行位移,不需要进行任何的修改
    <ul>
      <li key="2015">Duke</li>
      <li key="2016">Villanova</li>
    </ul><ul>
      <li key="2015">Duke</li>
      <li key="2014">Connecticut</li>
      <li key="2016">Villanova</li>
    </ul>
    
  • key的注意事项:

    • key应该是唯一的;
    • key不要使用随机数(随机数在下一次render时,会重新生成一个数字);
    • 使用index作为key,对性能是没有优化的;