Hooks-useEvent

useEvent解决了一个问题:如何同时保持函数引用不变与访问到最新状态

因为useCallback存在保持函数引用稳定时状态不更新的问题,所以引入了useEventhook。

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
import React, { useState, useCallback, useRef, useLayoutEffect } from 'react';
import { Button } from '../components';

export default function UseEvent() {
const [count4, setCount4] = useState(0);
const [count5, setCount5] = useState(0);

// 为了保持函数引用不变,依赖项为空
const stableClickFn = useCallback(() => {
// 访问到的总是初始值
setCount4(count4 + 1);
}, []);

// 使用useEvent,保持函数引用不变的同时状态实时更新
const stableClickFn2 = useEvent(() => {
setCount5(count5 + 1);
});

return (
<div>
<h1>useCallback + []</h1>
<Button onClickButton={stableClickFn}>stable button4</Button>

<div>count 只会更新一次</div>
<div>count4: {count4}</div>

<h1>useEvent</h1>
<Button onClickButton={stableClickFn2}>stable button4</Button>

<div>count 只会更新一次</div>
<div>count5: {count5}</div>
</div>
);
}

实现原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 模仿useEvent
function useEvent(handler) {
const handlerRef = useRef(null);

// In a real implementation, this would run before layout effects
useLayoutEffect(() => {
handlerRef.current = handler;
});

return useCallback((...args) => {
// In a real implementation, this would throw if called during render
const fn = handlerRef.current;
return fn(...args);
}, []);
}

理解一下:

  1. 为了返回一个稳定引用,那么最后返回的函数一定使用useCallback和依赖项空数组[]
  2. 又要在函数执行时访问到最新值,那么每次都要拿最新函数来执行,所以在 Hook 里使用 Ref 存储每次接收到的最新函数引用,在执行函数时,实际上执行的是最新的函数引用。
Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×