React面试题,封装useEffect

在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;

工作原理

  1. useRefuseRef 创建一个可变的引用对象,其值在组件的整个生命周期内保持不变。这里用它来存储一个布尔值 skipFirst,初始值为 true
  2. useEffect
    • useEffect 中,首先检查 skipFirst.current 的值:
      • 如果是 true,说明是第一次渲染,直接跳过,并将 skipFirst.current 设置为 false
      • 如果是 false,说明不是第一次渲染,执行传入的副作用函数 effect
    • 如果 effect 返回了一个清理函数(即返回值是一个函数),则在组件卸载或依赖项变化时执行该清理函数。
  3. 依赖项dependencies 数组用于控制 useEffect 的执行时机,与普通 useEffect 的行为一致。

示例解释

  • 首次渲染skipFirst.currenttrue,跳过执行 effect,不执行任何操作。
  • 后续依赖变化skipFirst.currentfalse,执行 effect,并返回清理函数(如果有)。
  • 组件卸载 :当组件卸载时,useEffect 的返回值(清理函数)会被执行,确保资源被正确清理。

注意事项

  • 确保 effect 函数的返回值是一个函数,否则清理逻辑不会被触发。
  • 如果依赖项数组为空([]),则副作用函数只会在组件首次渲染后和组件卸载时执行。
  • 如果依赖项数组中有值,则副作用函数会在依赖项变化时执行,并在组件卸载时执行清理逻辑。

通过这种方式,你可以实现一个自定义的 useEffect,使其在首次渲染时不执行,但在后续依赖变化时执行,并且在组件卸载时执行清理逻辑。

相关推荐
Larcher4 小时前
React Router 不只是页面跳转:从 SPA 路由到权限守卫的完整实践
javascript·后端
Larcher4 小时前
大模型为什么每次回答都不一样?一文搞懂 Temperature、Top K 与 Top P
javascript·后端
用户938515635077 小时前
从零在浏览器里跑 DeepSeek-R1:WebGPU + Transformer.js 全链路实战
前端·设计模式·typescript
CodeSheep7 小时前
稚晖君公司人事大变动,来了!
前端·后端·程序员
鱼樱前端8 小时前
用 AI 做内容变收入
前端·人工智能·ai编程
eric-sjq8 小时前
10 分钟实战:用 0.6B 本地模型生成中文网页(WanlyFrontend + 编译器全流程)
javascript·机器学习·自然语言处理·html
浮生望8 小时前
React + TypeScript 组件设计进阶:从类型约束到无状态组件的三次进化
前端
To_OC8 小时前
LC 438 找到所有字母异位词:暴力超时后,我靠滑动窗口一招搞定
javascript·算法·leetcode
90后的晨仔8 小时前
Mac 开发 uni-app 终极方案:让安卓模拟器彻底脱离 Android Studio 独立运行
前端·vue.js
90后的晨仔8 小时前
别再搞混了!uni-app 中 node_modules 和 uni_modules 到底是什么关系?
前端