资源清理策略
- 网络请求:
- 使用
AbortController
来取消未完成的网络请求。在组件挂载时创建 AbortController
实例,在组件卸载时调用 abort
方法。这样可以避免在组件卸载后,网络请求继续执行,从而防止潜在的内存泄漏和数据更新异常。
- 对于
fetch
,可以将 signal
属性传递给 fetch
请求。对于 axios
,可以使用 CancelToken
。
- DOM 元素操作:
- 在组件卸载时,移除组件所创建的 DOM 元素。可以使用
useRef
来引用 DOM 元素,然后在 useEffect
的清理函数中调用 remove
方法来移除该元素。
- 如果涉及到 canvas 绘制,在移除 canvas 元素之前,停止相关的绘制操作(例如停止
requestAnimationFrame
动画循环,如果有的话)。
- 动画资源:
- 对于 CSS 动画,可以通过在组件卸载时移除相关的 CSS 类来停止动画。
- 对于
requestAnimationFrame
,在组件卸载时取消动画循环。可以使用一个变量来存储 requestAnimationFrame
返回的 ID,然后在清理函数中调用 cancelAnimationFrame
。
代码示例
import React, { useEffect, useRef } from'react';
import axios from 'axios';
const ComplexComponent = () => {
const canvasRef = useRef(null);
const animationFrameIdRef = useRef(null);
const abortControllerRef = useRef(new AbortController());
useEffect(() => {
// 创建 canvas 元素
const canvas = document.createElement('canvas');
canvasRef.current = canvas;
document.body.appendChild(canvas);
// 网络请求
const fetchData = async () => {
try {
const response = await axios.get('/api/data', {
cancelToken: new axios.CancelToken((c) => {
abortControllerRef.current.signal.addEventListener('abort', c);
})
});
console.log('Data fetched:', response.data);
} catch (error) {
if (!axios.isCancel(error)) {
console.error('Error fetching data:', error);
}
}
};
fetchData();
// CSS 动画,添加类名触发动画
document.body.classList.add('my - css - animation');
// requestAnimationFrame 动画
const animate = () => {
// 这里是动画逻辑
animationFrameIdRef.current = requestAnimationFrame(animate);
};
animationFrameIdRef.current = requestAnimationFrame(animate);
return () => {
// 清理网络请求
abortControllerRef.current.abort();
// 清理 DOM 元素
if (canvasRef.current) {
canvasRef.current.remove();
}
// 清理 CSS 动画
document.body.classList.remove('my - css - animation');
// 清理 requestAnimationFrame 动画
if (animationFrameIdRef.current) {
cancelAnimationFrame(animationFrameIdRef.current);
}
};
}, []);
return <div>Complex Component</div>;
};
export default ComplexComponent;
性能影响及避免新问题
- 性能影响:
- 网络请求的取消应优先处理,因为未完成的网络请求可能会占用网络资源,并且如果继续执行可能会导致数据更新到已经卸载的组件,从而引发性能问题和潜在的错误。
- DOM 元素的移除和动画的停止可以并行处理。移除 DOM 元素可以释放内存,而停止动画可以避免不必要的计算。
- 避免新问题:
- 通过使用
AbortController
和 CancelToken
确保网络请求在组件卸载时被正确取消,避免资源未加载完成就进行清理导致的异常。
- 对于 DOM 元素和动画,在清理之前先检查相关的引用是否存在,避免在不存在的元素上执行操作,从而防止新的异常。例如,在移除 canvas 元素之前检查
canvasRef.current
是否存在,在取消 requestAnimationFrame
之前检查 animationFrameIdRef.current
是否存在。