useState与useEffect原理
# useState与useEffect实现原理
import React from "react";
import * as ReactDOMClient from "react-dom/client";
const AppDOM = React.createRef()
let root
let stateArrs = []
let stateIndex = 0
let effectIndex = 0
const useState = (initValue) => {
stateArrs[stateIndex] = stateArrs[stateIndex] ?? initValue
const setState = (index) => {
stateIndex ++
return (newState) => {
stateArrs[index] = newState
if(!root){
root = ReactDOMClient.createRoot(AppDOM.current);
}
stateIndex = 0
effectIndex = 0
root.render(<Children />);
}
}
return [stateArrs[stateIndex], setState(stateIndex)]
}
let preArrs = []
const useEffect = (callback, relyArrs) => {
if(!preArrs[effectIndex] || !relyArrs.every((item, index) => item === preArrs[effectIndex][index])){
callback()
}
preArrs[effectIndex] = relyArrs
effectIndex++
}
const Children = () => {
const [count, setCount] = useState(1)
const [count2, setCount2] = useState(3)
useEffect(() => {
console.log('count发生变化')
},[count])
useEffect(() => {
console.log('count2发生变化')
},[count2])
useEffect(() => {
console.log('count3发生变化')
},[])
return (
<>
<div>useState与useEffect原理</div>
<div>count1值为:{count}</div>
<button onClick={() => setCount(count + 1)}>改变count1</button>
<div>count2值为:{count2}</div>
<button onClick={() => setCount2(count2 + 1)}>改变count2</button>
</>
)
}
const App = () => {
return (
<div ref={AppDOM}>
<Children/>
</div>
)
}
export default App
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# 1. useState原理
1.useState是依赖于外部一个变量stateArrs
用来存储每次的状态,由于可以多次调用,所以这个变量是个数组类型。每次执行useState取出对应索引stateIndex
的值,进行返回。
2.setState是利用了闭包的思想,将每次执行useState时的索引stateIndex
存下来,作为setState的私有变量。这样每次调用setState就会针对具体的索引值stateArrs[stateIndex]
去修改了。
3.调用setState时,state改变后,会重新render,把stateIndex
恢复初始值0
# 2. useEffect原理
1.useEffect也是依赖于外部变量preArrs
,每次调用useEfffect()都会与上次保存的依赖值做对比,如果不相同就执行callback回调。
2.由于useEffect可以被多次调用,所以preArrs
也是一个数组,也需要一个变量effectIndex
来记录每次调用的索引。
# 常见问题
1. useState是同步还是异步?
useState 本身是同步的,调用 useState 函数返回一个更新后的状态和更新状态的函数,这个更新状态的函数可以被同步调用。在调用状态更新函数时,React 会立即将新状态更新到组件中并重新渲染组件。但是,因为 React 对状态的批量更新机制,可能会导致在一个 setState 中多个状态更新合并成一次渲染,这种情况下,setState 是异步的。当多个 setState 进行批量更新时,React 会在当前执行栈完成后才更新组件。但是,这种情况是由 React 决定的,对于我们的代码来说,setState 仍然是同步的。
编辑 (opens new window)
上次更新: 2023/02/16