模拟useState
useState原理深入
1.const [n,setN] = React.useState(0)
2.分析
- setN会修改数据x,将n+1存入x
- setN一定会触发App的重新渲染(re-render)
- useState肯定会从x读取n的最新值
- 每个组件都有自己的数据x,我们将其命名为state
3.自己写一个useState
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
let _state
const myUseState = initialValue=>{
_state = _state===undefined?initalValue:_state
const setState = (newValue) =>{
_state = newValue
render()
}
return [_state,setState]
}
const render = ()=>{
ReactDOM.render(<App />,rootElement)
}
const App = ()=>{
const [n,setN] = myUseState(0)
}
|
4.但是myUseState有问题,如果调用了两次myUseState会有冲突
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
let _state = []
let index = 0
const myUseState = initialValue=>{
const currentIndex = index
_state[currentIndex] = _state[currentIndex]===undefined?initalValue:_state
const setState = (newValue) =>{
_state[currentIndex] = newValue
render()
}
index += 1
return [_state[currentIndex],setState]
}
const render = ()=>{
index = 0
ReactDOM.render(<App />,rootElement)
}
const App = ()=>{
const [n,setN] = myUseState(0)
const [m,setM] = myUseState(0)
}
|
5.因为顺序的原因,myUse不能放在if..else..里,可以自己尝试一下原版的useState,提示组件调用的Hook不能有顺序变化
6.myUseState还有一个问题,两个组件不能同时用这个_state和index
- React的解决办法,放在组件对应的虚拟节点对象上
7.总结
- 每个函数组件对应一个React节点
- 每个节点保存着state和index
- useState会读取state[index]
- index由useState出现的顺序决定(当组件重新渲染的时候会将index置为0,然后根据调用的顺序来取用state,所以不能把useState放在if判断里)
- setState会修改state,并触发更新
8.由于useState产生新的n,并不直接修改原来的n,所以该状态没有贯穿始终,可以贯穿始终的状态
- useRef
- useRef不仅可以用于div,还能用于任意数据(它改变数据就是改变当前数据),但不能自己触发render,可以用setN触发
- useContext不仅能贯穿始终,还能贯穿不同组件
- 同时ref还可以用来引用DOM对象