目的
理清 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
}
}
}
具体实现还得看源码