在React中,useEffect 是一个非常常用的钩子,用于处理副作用(如数据获取、订阅或手动更改 DOM)。默认情况下,useEffect 在组件首次渲染时和每次依赖项变化时都会执行。如果你希望封装一个 useEffect,使其在第一次渲染时不执行,可以通过一个自定义钩子来实现。
自定义钩子:useEffectSkipFirst
tsx
import { useEffect, useRef } from 'react';
// 自定义钩子,跳过第一次执行,支持清理逻辑
function useEffectSkipFirst(effect: () => void | (() => void), dependencies: any[] = []) {
const skipFirst = useRef(true); // 使用 useRef 来存储是否跳过第一次的状态
useEffect(() => {
if (skipFirst.current) {
skipFirst.current = false; // 第一次时跳过,并将状态改为 false
return undefined; // 不执行任何操作
}
// 执行传入的副作用函数
const cleanup = effect();
// 如果副作用函数返回了一个清理函数,则在组件卸载或依赖变化时执行清理逻辑
return cleanup;
}, dependencies); // dependencies 是依赖项数组
}
export default useEffectSkipFirst;
使用方法
tsx
import React from 'react';
import useEffectSkipFirst from './useEffectSkipFirst';
const MyComponent = () => {
useEffectSkipFirst(() => {
console.log('This effect will not run on the first render');
// 返回清理逻辑
return () => {
console.log('Cleanup logic executed on component unmount or dependency change');
};
}, []); // 依赖项为空数组,表示只在依赖项变化时执行
return <div>My Component</div>;
};
export default MyComponent;
工作原理
useRef:useRef创建一个可变的引用对象,其值在组件的整个生命周期内保持不变。这里用它来存储一个布尔值skipFirst,初始值为true。useEffect:- 在
useEffect中,首先检查skipFirst.current的值:- 如果是
true,说明是第一次渲染,直接跳过,并将skipFirst.current设置为false。 - 如果是
false,说明不是第一次渲染,执行传入的副作用函数effect。
- 如果是
- 如果
effect返回了一个清理函数(即返回值是一个函数),则在组件卸载或依赖项变化时执行该清理函数。
- 在
- 依赖项 :
dependencies数组用于控制useEffect的执行时机,与普通useEffect的行为一致。
示例解释
- 首次渲染 :
skipFirst.current为true,跳过执行effect,不执行任何操作。 - 后续依赖变化 :
skipFirst.current为false,执行effect,并返回清理函数(如果有)。 - 组件卸载 :当组件卸载时,
useEffect的返回值(清理函数)会被执行,确保资源被正确清理。
注意事项
- 确保
effect函数的返回值是一个函数,否则清理逻辑不会被触发。 - 如果依赖项数组为空(
[]),则副作用函数只会在组件首次渲染后和组件卸载时执行。 - 如果依赖项数组中有值,则副作用函数会在依赖项变化时执行,并在组件卸载时执行清理逻辑。
通过这种方式,你可以实现一个自定义的 useEffect,使其在首次渲染时不执行,但在后续依赖变化时执行,并且在组件卸载时执行清理逻辑。