useRef
# useRef原理
import React from "react";
import * as ReactDOMClient from "react-dom/client";
const AppDOM = React.createRef()
let root
let refIndex = 0
const render = () => {
if(!root){
root = ReactDOMClient.createRoot(AppDOM.current);
}
refIndex = 0
root.render(<Children />);
}
const refs = []
const useRef = (initVal) => {
if(!refs[refIndex]){
refs[refIndex] = {current: initVal}
}
refIndex++
return refs[refIndex - 1]
}
const Children = () => {
const count1 = useRef(0)
const count2 = useRef(0)
const showCounts = () => {
setTimeout(() => {
alert(`count1:${count1.current} count2:${count2.current}`)
},5000)
}
return (
<div>
<div>
count1值为:{count1.current}
<button onClick={() => count1.current = ++count1.current}>
改变count1
</button>
</div>
<div>
count2值为:{count2.current}
<button onClick={() => count2.current = count2.current + 1}>
改变count2
</button>
</div>
<button onClick={() => render()}>
重新render
</button>
<button onClick={showCounts}>
5秒后输出count1、count2
</button>
</div>
)
}
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
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
# 与useState区别
- useRef()是返回一个对象
{current: state}
,所以不管什么时候取useRef赋值的变量,都是最新的值。因为每次返回都是同一个对象的引用,每次修改count = count.current + 1
都是改的这个对象的属性。 - 而useState每次调用返回的都是一个新的引用,所以就会造成下面这个问题:
import {useState} from "react";
const App = () => {
const [count, setCount] = useState(0)
const handleShowClick = () => {
setTimeout(() => {
alert(`count值为${count}`)
},5000)
}
return (
<div>
<button onClick={() => setCount(count + 1)}>count加1</button>
<button onClick={handleShowClick}>展示count</button>
</div>
)
}
export default App
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
点击【展示count】按钮后,5秒内多次点击【count加1】,最终展示效果为"count值为0"。
这是因为每次render都会有一个作用域,点击【展示count】后,调用handleShowClick,此时这个方法体内拿到的count是0,可以理解为函数组件每次渲染都会形成一个闭包,闭包内有自己的作用域。所以5秒内不管改变多少次count值,最终展示效果都是"count为0"。
# 如何解决useState引起的闭包问题。
用useRef替换useState
import {useRef} from "react";
const App = () => {
const count = useRef(0)
const handleShowClick = () => {
setTimeout(() => {
alert(`count值为${count.current}`)
},5000)
}
return (
<div>
<button onClick={() => count.current = count.current + 1}>count加1</button>
<button onClick={handleShowClick}>展示count</button>
</div>
)
}
export default App
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 使用场景
- 存dom
- 存值(任何时候都可以拿到最新值)
编辑 (opens new window)
上次更新: 2023/02/16