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,使其在首次渲染时不执行,但在后续依赖变化时执行,并且在组件卸载时执行清理逻辑。

相关推荐
daols885 分钟前
vxe-table 渲染器教程一:实现金额输入控件
javascript·vue.js·vxe-table
不好听61318 分钟前
React 核心概念:JSX、组件与数据驱动
前端·react.js
触底反弹19 分钟前
🔥 React 零基础入门(中):500 行屎山代码到组件化的蜕变
前端·javascript·react.js
不好听61320 分钟前
React vs Vue:两大前端框架技术选型深度对比
前端·vue.js·react.js
GuWenyue21 分钟前
Cursor黑盒拆解!1套LangChain.js手写Mini编程Agent,自动生成React项目,效率提升60%
前端·数据库·人工智能
GuWenyue21 分钟前
传统Agent工具两大痛点!300行代码落地MCP跨语言工具,彻底解耦LLM与工具
前端·人工智能·算法
小林ixn1 小时前
从 onclick 到 React 合成事件,再到完整应用逻辑:一次前端架构的深度剖析
前端·react.js·前端框架
Csvn2 小时前
🧩「找不到模块」排查全记录——Monorepo 下 TypeScript 路径别名的 5 种「不通」与根治方案
前端
腻害兔2 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:字典、短信、邮件、通知——后台系统的“基础设施四件套“!
java·前端·vue.js·产品经理·ai编程
CodexDave2 小时前
MySQL事务隔离级别与MVCC机制解析
前端·数据库·mysql·nginx·性能优化·负载均衡