# 自定义hooks
# useAsyncEffect
下面是 useAsyncEffect 的完整源代码:
import { useEffect, useRef } from "react";
function useAsyncEffect(asyncFunc, deps) {
const isMountedRef = useRef(true);
useEffect(() => {
return () => {
isMountedRef.current = false;
};
}, []);
useEffect(() => {
const runAsyncFunc = async () => {
try {
await asyncFunc();
} catch (error) {
if (isMountedRef.current) {
throw error;
}
}
};
runAsyncFunc();
return () => {
isMountedRef.current = false;
};
}, deps);
}
export default useAsyncEffect;
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
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
useAsyncEffect 使用了两个 useEffect 钩子函数来管理异步副作用:
- 第一个
useEffect钩子函数是用来跟踪组件是否被卸载的。它会在组件第一次挂载时运行,返回一个函数,在组件卸载时更新isMountedRef的值为false。 - 第二个
useEffect钩子函数是用来执行异步函数和捕获错误的。它会在组件挂载后或者依赖项变化时运行。每次运行时,它都会定义一个异步函数runAsyncFunc来运行传递给useAsyncEffect的异步回调函数。如果异步函数没有抛出错误,它将继续运行,直到组件被卸载。如果异步函数抛出了错误,并且组件尚未被卸载,将抛出错误。
这里使用了一个 isMountedRef 来记录组件是否已经被卸载。在 runAsyncFunc 函数中,使用 isMountedRef.current 来判断组件是否已被卸载。如果组件已经被卸载,runAsyncFunc 将不会继续执行,因此不会产生任何错误。如果组件尚未被卸载,runAsyncFunc 将抛出错误,并向上层其它异常处理层传递该错误。
最后,useAsyncEffect 返回 undefined,因为它并不需要返回任何值。
这就是 useAsyncEffect 的完整源代码。
# useEffect和useAsyncEffect
useEffect用于处理副作用,包括同步和异步操作,但不会等待异步操作完成。useAsyncEffect通常用于处理异步操作,它会等待异步操作完成后再触发下一次渲染,确保渲染时数据已经准备好。
# useEventListener
import { useEffect } from 'react';
function useEventListener(eventName, handler, element = window) {
useEffect(() => {
if (element && element.addEventListener) {
// 添加事件监听器
element.addEventListener(eventName, handler);
// 清理函数,用于卸载组件时移除事件监听器
return () => {
element.removeEventListener(eventName, handler);
};
}
}, [eventName, handler, element]);
}
export default useEventListener;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
useEventListener 自动处理了事件监听器的清理,它会在组件卸载时自动移除事件监听器,以防止内存泄漏。
addEventListener 要手动移除事件监听器,否则可能会导致内存泄漏。