likes
comments
collection
share

自己模拟一个setState更新机制

作者站长头像
站长
· 阅读数 9

自己模拟一个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的时候需要重新建立索引,并执行创建阶段。
     
     

上述只是一个模拟的过程,只是便于理解一些。如果想要知道具体的代码,请阅读源代码。