React-setState的实现原理

150 阅读2分钟

前言

  • 组件的数据来源有两个地方,分别是属性对象和状态对象
  • 属性是父组件传递过来的
  • 状态是自己内部维护的,改变状态唯一的方式就是setState
  • 属性和状态的变化都会影响视图更新
  • 不要直接修改State,构造函数是唯一可以给this.state赋值的地方

类组件状态更新例子

image.png

我们现在来实现setState

在Conponent.js里

image.png

  • 初始化state和更新器

当调用setState时

image.png

Updater类

image.png

  • 保存类Component类实例
  • 保存要更新的状态
  • 调setState的时候,里面会调Updater的addState方法,将要更新的状态保存起来,然后调emitUpdate发射更新
  • emitUpdate里会调updateComponent进行状态更新
  • updateComponent会判断当前更新队列里是否要更新,如果有将要更新的数据,则调shouldUpdate

getState方法

image.png

  • 先拿到老状态,然后循环将要更新的状态队列,新老进行合并,用新状态覆盖老的状态
  • 用完之后清空调将要更新的状态队列
  • 然后返回新老状态合并后的新状态
  • 这个方法在计算新状态

shouldUpdate方法

image.png

  • 让类组件实例的状态state等于新状态
  • 然后调用类组件实例的forceUpdate方法

我们先去react-dom.js里把上次渲染的虚拟dom缓存到组件的实例上

image.png

在创建真实DOM的时候,把虚拟DOM和真实DOM进行关联

image.png

  • 把虚拟DOM生成的真实DOM缓存到虚拟DOM上

findDOM方法

image.png

  • 从虚拟DOM获取真实DOM
  • 真实DOM可能没有,如果没有返回null
  • 这个地方有点绕,需要理解,如果虚拟dom上缓存的有真实dom,那么说明这个虚拟dom是一个原生组件,因为只有type是文本或者字符串的时候才会缓存真实dom到虚拟dom上。这个逻辑看上篇文章可以找到答案,在判断type的时候会判断是否是一个函数,如果是一个函数,则继续判断是类组件还是函数组件
  • 因为函数组件可能返回的还是组件,可能有很多层, 所以这里需要递归

forceUpdate方法

image.png

  • 强制更新,更新真实dom
  • 拿到老的虚拟dom
  • 通过findDom方法去拿到真实dom
  • 调用实例的render方法,拿到新的虚拟dom
  • 调用compareToVdom进行更新
  • 把新虚拟dom成为老的虚拟dom

compareToVdom方法

image.png

  • parentDOM是组件的父节点
  • 找到老的真实dom,创建新的dom
  • 把老的真实dom替换为新的真实dom

我们此处只是简单的实现,并没有进行DOM-DIFF,我们后续会进行实现

下篇我们来实现合成事件和批量更新