数组模拟useState

目的

理清 useState 的实现机制

使用方式和执行过程

  • const [count1, setCount1] = useState(0);
  • useState(0)可以设置初始值并返回初始值以及更改 state 的方法
  • 调用 useState 后页面就会重新渲染

代码部分

重点在于实现 useState ,render 的过程就是用 react 的原生 render

由于

  • useState 是个函数,返回一个数组(Array)且 Array[0]是 state 值,Array[1]是更改 state 的方法
  • 多个状态之前不会影响,每次 render 都会找到对应的正确值
  • 第 N 次 render 时可以拿到上一次的 state

所以

  • 保存 state 的数组和索引都需要在函数外部,不能每次调用 useState 都重置了
  • render 后要把索引重置为 0,不然匹配不到对应的 state

代码如下

import React from "react";
import ReactDOM from "react-dom";

let hookStates = [];
let hookIndex = 0;
function useState(initialState) {
  const currentIndex = hookIndex;
  hookStates[currentIndex] = hookStates[currentIndex] || initialState;

  function setState(newState) {
    hookStates[currentIndex] = newState;
    render();
  }
  hookIndex += 1;
  return [hookStates[currentIndex], setState];
}

function App() {
  const [count1, setCount1] = useState(0);
  const [count2, setCount2] = useState(0);
  return (
    <div>
      <p>count1: {count1}</p>
      <p>count2: {count2}</p>
      <button
        onClick={() => {
          setCount1(count1 + 1);
        }}
      >
        +1
      </button>
      <button onClick={() => setCount2(count2 + 1)}>+1</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
function render() {
  ReactDOM.render(<App />, rootElement);
  hookIndex = 0;
}
render();

最后

上面都是 useState 的模拟实现,我们使用数组和索引来实现的 useState 的基本原理,源码里涉及 fiber,任务调度等等,由

{
 memoizedState: any,
 baseState: any,
 baseUpdate: Update<any> | null,
 queue: UpdateQueue<any> | null,
 next: Hook | null,
}

队列里的 next 单向链表

{
 memoizedState: 'foo',
 next: {
   memoizedState: 'bar',
   next: {
     memoizedState: 'baz',
     next: null
   }
 }
}

具体实现还得看源码

发表评论

您的电子邮箱地址不会被公开。