State Hook 是什么
useState
是允许你在 React 函数组件中添加 state 的 Hook。它是一种新方法,与 class 里面的this.state
提供的功能完全相同。
useState
定义了一个"state 变量",该变量即便在函数退出后,也会被 React 保留。
useState()
方法里面唯一的参数就是初始 state,我们可以按需使用数字或字符串对其进行赋值,而不一定是对象(与 class 的不同)。 如果想要在 state 中存储两个不同的变量,那就调用useState()
两次。
useState()
返回值为:当前 state 以及更新 state 的函数。
简单实现 useState
1. 当只使用一次 useState 的实现
import React from 'react';
import ReactDOM from 'react-dom';
const rootElement = document.getElementById('root');
let _state // 声明在函数外面,这样不会被 myUseState 重置
const myUseState = initialValue => {
_state = _state === undefined ? initialValue : _state
const setState = newValue => {
_state = newValue;
render();
};
return [_state, setState];
};
const render = () => {
ReactDOM.render(<App/>, rootElement); //简单粗暴的直接将整个组件 render
}
function App() {
const [n, setN] = myUseState(0);
return (
<div className="App">
<p>{n}</p>
<p>
<button onClick={() => setN(n + 1)}>+1</button>
</p>
</div>
);
}
ReactDOM.render(<App/>, rootElement);
这样就简单实现了,点击 +1 按钮,显示的数字也 +1 的功能。
但如果一个组件,用了两个useState()
的话,这样做就不行了,后面的 useState 会把前一项给覆盖掉。所以我们把_state
做成数组。
2. 改进:使用数组存储_state
let _state = []; // 数组
let index = 0;
const myUseState = initialValue => {
const currentIndex = index;
_state[currentIndex] =
_state[currentIndex] === undefined ? initialValue : _state[currentIndex];
const setState = newValue => {
_state[currentIndex] = newValue;
render();
};
index += 1;
return [_state[currentIndex], setState];
};
const render = () => {
index = 0; // 重置 index
ReactDOM.render(<App/>, rootElement);
};
function App() {
const [n, setN] = myUseState(0);
const [m, setM] = myUseState(0);
return (
<div className="App">
<p>{n}</p>
<p>
<button onClick={() => setN(n + 1)}>n+1</button>
</p>
<p>{m}</p>
<p>
<button onClick={() => setM(m + 1)}>m+1</button>
</p>
</div>
);
}
ReactDOM.render(<App/>, rootElement);
现在,也可以成功使用多个useState
啦。
3. _state
数组方案缺点
因为是数组,所以useState
非常依赖调用顺序。每次渲染时的顺序必须保证和第一次渲染时顺序完全一致。
所以 React 中 Hook 只能在函数最外层调用,不能在循环、条件判断或者子函数中调用。
4. 给每个组件创建一个 _state
和 index
可以将每个组件创建的属于自己的_state
和 index
,放在组件对应的虚拟节点对象上。
React 中,React虚拟节点是 FiberNode,_state 的真实名称为 memoizedState,index 的实现则是使用了链表。
总结
- 每个函数组件对应一个 React 节点。
- 每个节点保存着 state 和 index
- useState 会读取 state[index]
- index 由 useState 出现的顺序决定
- setState 会修改 state,并触发更新