React与Vue状态更新原理对比

2,295 阅读3分钟

为什么要学习源码呢?每个人都有不同的看法,这就好比开车一样,如果你只会开车不会修理的话,那么车开到一半怎么办?所以想要使用好React,或多或少都得了解一些React的源码。毕竟靠人不如靠自己!自己动手丰衣足食!!

本片文章内容比较简单,为什么呢?如果我把源码直接拿出来一步一步的分析,很多人会一头雾水,搞不懂在干什么,所以干脆站的高一点,主要讲一下两个框架在更新状态时的原理对比。只有先懂得了状态更新的原理,看源码才不会很吃力。

React基本组成

这里我们必须明白React的组成,React是由 调度器协调器渲染器 这三大部分组成。

  1. 调度器: 调度器可以理解成控制室,每次更新根据优先级来调度更新,高优先级的更新可以打断低优先级的更新。

  2. 协调器: 协调器就是我们经常提到的Diff算法的部分,这个部分主要的作用就是 对比currentFiber和JSX对象的差异生成 workInProgressFiber。 然后由渲染器渲染。

  3. 渲染器: 渲染器就很好理解了,主要的作用就是将生成好的 workInProgressFiber 渲染到页面。

基本的运行逻辑为: 状态的更新经由 控制器根据优先级来调度,高优先级的更新可以打断低优先级的更新,然后经由协调器进行Diff生成workInProgressFiber,再由渲染器进行渲染。

React状态更新

经过了基本组成和运行逻辑的介绍,现在我们进入正题,看看状态跟新具体做了什么事情!

基本代码:

import React from "react";

const App = () => {
  const [num, setNum] = React.useState(1);
  const handleClickBut = () => {
    setNum((num) => num + 1);
  };
  React.useEffect(() => {}, [num]);
  return (
    <div>
      {num}
      <button onClick={handleClickBut}>增加</button>
    </div>
  );
};

这个例子很简单,用户点击增加按钮,调用setNum触发状态更新。

状态更新流程

主要流程如下图所示:

React状态更新流程.png

关键步骤分析
  1. dispatchAction ---> basicStateReducer 阶段

    在这个阶段当中,会创建一个新的undate对象和之前的queue.pending形成一个环状链表。然后在根据传入的action计算得出最新的memoizedState。

  2. scheduleUpdateOnFiber ---> performSyncWorkOnRoot || performConcurrentWorkOnRoot 阶段

    在这个阶段中,React主要进行优先级的调度,根据创建应用的模式不同调用不同模式的 Diff 方法(performSyncWorkOnRoot || performConcurrentWorkOnRoot) Diff逻辑一样,只是在Diff之前会做不同的处理。不要错误理解

  3. renderRootComcurrent || renderRootSync ---> commitRoot 阶段

    在这个阶段中,React主要进行Diff, 对比currentFiber和JSX对象的差异生成 workInProgressFiber。 然后由渲染器渲染。

  4. commitRoot ---> commitLayoutEffects 阶段

    在这个阶段, Reac主要进行渲染DOM,并且调用生命周期。

Vue基本组成

对于Vue的基本原理我想我就不用说了吧!官网已经说得很清楚了!!

data.png

其实总结下来也就是: 当状态改变Object.defineProperty中的set触发,通知相关的依赖,由Watcher触发对应的组件进行更新,以达到视图更新的目的。

Vue状态更新

基本代码:

<template>
  <div>
    {{ num }}
    <button @click="num++">增加</button>
  </div>
</template>
<script>
export default {
  data() {
    return {
      num: 0,
    };
  },
};
</script>

点击按钮触发num加1Z,状态改变触发更新流程。

状态更新流程

主要的流程如图所示:

Vue状态更新.png

关键步骤分析
  1. proxySetter ---> dep.notify() 阶段

    在这个阶段,Vue主要进行了 状态的改变和根据依赖通知更新。

  2. subs[i].update() ---> watcher.run() 阶段

    在这个阶段,Vue主要进行了由Watcher监听到了改变,然后更新视图组件的过程。

  3. updateComponent ---> updated

    在这个阶段,Vue主要进行了Diff,并且将最终的DOM渲染到视图中。并且调用更新时的生命周期函数。

往期精彩