自己模拟一个setState更新机制
自己模拟一个setState更新机制
在使用useState 的时候同事问了我一个问题,为什么使用const 解构出来的变量可以更改。
如果知道的同学就会说他是从useState中解构出来的,每一次解构的东西都是新的,所以使用const变量结构是没有问题的,然后我在想它里面是怎么运行的呢。
这样自己就稍微模拟一下最简单的useState方法去看一下如何更新的。
一、首先创建两个componment并挂载Dom
代码解释在最下方。
import React form 'react';
import { render } form 'react-dom';
const elementRoot=document.getElementById('app')
// 首先创建一个数组,因为我们都知道state存储方式是以数组形式存储的,一定要是全局的state,不然后期无法重新创建索引
let stateList=[];
//然后创建数组的索引默认从0开始
let index=0;
//下面就是我们模拟的useState更新的方法了
const myUseState=(initialValue)=>{
// 这里很重要需要创建一个变量存储索引
const indexVariable=index;
// 这里是当第一次创建stateList的索引的时候因为没有内容所以需要有一个容错。
stateList[indexVariable]=stateList[indexVariable]===null?initialValue:stateList[indexVariable]
//这里就是我们的更新方法了
const setState=(newValue)=>{
stateList[indexVariable]=newValue;
// 这个render很重要,为什么要render() 因为每一次更新完之后需要重新建立索引。
renderDom();
}
// 这里的index++是因为每一个调用myUseState方法的时候都需要在原有的索引上面累加
index++;
// 最后就要返回一个新的数组,这就可以解释为什么“每一次解构的东西都是新的”原因了。
return [stateList[indexVariable], setState];
}
const renderDom=()=>{
index=0;
render(<App />, elementRoot);
}
// 自增
const Add=()=>{
const [myState,setMyState]=myUseState(0);
return (
<div>
<button onCLick={()=>{setMyState(myState+1)}}>自增</button>
</div>
)
}
// 自减
const Decrement=()=>{
const [myState,setMyState]=myUseState(0);
return (
<div>
<button onCLick={()=>{setMyState(myState-1)}}>自减</button>
</div>
)
}
const App=()=>{
return (
<div>
<Add/>
<Decrement/>
</div>
)
}
// 挂载App
render(<App />, elementRoot);
二、下面我们来捋一下执行顺序
1、创建阶段
1、当挂载阶段我们程序自上而下执行,每一次遇到myUseState的方法时就会执行一次。
2、第一次执行的时候index=0,将index赋给indexVariable。这个要注意这是最关键的一步。下面会讲解
3、判断,当stateList[indexVariable]===null 的时候把初始值放到数组的索引处。
4、遇见第二个组件的之后继续执行myUseState的方法继续执行[1、2、3]步骤。
2、执行方法阶段
1、当我们点击自增或者自减的时候,程序就会执行setMyState方法,将新值传进去并将state对应下标的值更新。
2、然后执行renderDom方法,并执行创建阶段的[1、2、3]步骤。
三、在执行的阶段有一个困扰我半天的问题
1、为什么每次点击都能准确的更新到数组对应的下标?
答: 因为在创建阶段每次执行的时候都会创建一个闭包(这就是我在创建阶段的第二点中要赋值的原因)。
因为每一个闭包的indexVariable都不会被销毁,所以每一次执行setMyState的时候都可以正确找到数组对应的下标,并且更新他。
更新完之后从新renderDom.
这个解释就解答了在创建阶段第二步的时候要将index存储
2、那为什么要在renderDom中将index重置呢?
答:因为在重新renderDom的时候需要重新建立索引,并执行创建阶段。
上述只是一个模拟的过程,只是便于理解一些。如果想要知道具体的代码,请阅读源代码。
转载自:https://juejin.cn/post/7041152316594421774