useState
- 熟悉hooks的都知道,最常用的useState
- 大概用法
function App() {
const [x, setX] = useState(0)
return <div>
<h1>{x}</h1>
<button onClick={() => setX(x + 1)}>+1</button>
</div>
}
简单的实现一个useState
- 先模拟入参和出参
const rootElement = document.getElementById("root");
const render = () => {
ReactDOM.render(<App/>, root)
}
const useState = (initialValue) => {
function setState(newState) {
render()
}
return [state, setState]
}
function App() {
const [n, setN] = useState(0);
return (
<div className="App">
<h1>{n}</h1>
<button onClick={() => setN(n + 1)}>+1</button>
</div>
);
}
- 函数是存不住变量的,每次重新触发就会出现一个新的值,所以我们的state需要一个全局的state。
- 当完成下面这个,一个简单的useState就完成了。
- 可是它有bug,如果用到多个useState,他们共用的是一个state,那么就完蛋了,所以要改造一下。
let state;
const render = () => {
ReactDOM.render(<App/>, root)
}
const useState = (initialValue) => {
state = state === undefined ? initialValue : state
function setState(newState) {
state = newState
render()
}
return [state, setState]
}
- 把 state 初始化为一个数组,每次声明一个useState时候就在存放一个值,并且用index去代表值。
- 按照思路,每次触发useState就要 index + 1,代表要在state数组里面添加一个值。
- 每次重新setState重新渲染时候,就要index归0,不然会无限增大state这个数组。
let state = []
let index = 0
const render = () => {
index = 0
ReactDOM.render(<App/>, root)
}
const useState = (initialValue) => {
const currentIndex = index
state[currentIndex] = state[currentIndex] === undefined
? initialValue
: state[currentIndex]
function setState(newState) {
state[currentIndex] = newState
render()
}
index = index + 1
return [state[currentIndex], setState]
}
- 基本就完成了一个useState
- 运行代码
从简单例子,深入一点了解。
-
从简单的例子我们可以看出,react 对 useState 标识是用index去记录的,所以useState不能写在 if 里面,不然顺序就识别不了,我们常常看到这么一行报错。
就是这个原因,当然react内部的index是使用链表去实现的。
-
那么,每个组件的state声明在哪里? 其实它就声明在虚拟dom里头。
每次声明一个组件时候,组件内部就会生成一个 memoizedState 和 index (真正名称自己去查看)