useEffect的理解

一、核心概念:什么是 useEffect?

首先,先理解两个关键概念:
首先,先理解两个关键概念:

副作用(Side Effect):指组件渲染完成后需要执行的操作,比如:

数据请求(接口调用)
DOM 操作(修改 DOM 样式、添加事件监听)
订阅 / 取消订阅(定时器、WebSocket 连接)
手动修改 state(非通过 setState)

useEffect 作用:替代类组件中的 componentDidMount、componentDidUpdate、componentWillUnmount 三个生命周期方法,统一处理副作用逻辑。

二、基本语法

import { useEffect } from 'react';

function MyComponent() {
  // 基础用法
  useEffect(() => {
    // 副作用逻辑(渲染后执行)
    
    // 可选的清理函数(组件卸载/下一次effect执行前执行)
    return () => {
      // 清理操作(比如清除定时器、取消订阅)
    };
  }, [依赖项数组]); // 依赖项:控制effect何时重新执行
}

三、不同用法场景(核心重点)

场景 1:无依赖项数组 → 每次渲染后都执行

相当于类组件的 componentDidMount + componentDidUpdate。

import { useState, useEffect } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  // 每次组件渲染(count变化)后执行
  useEffect(() => {
    console.log(`当前count: ${count}`); // 渲染后打印count
    document.title = `点击了${count}次`; // 修改DOM(副作用)
  }); // 无依赖项数组

  return (
    <button onClick={() => setCount(count + 1)}>
      点击次数:{count}
    </button>
  );
}
执行时机:组件首次渲染后执行,每次状态更新(count 变化)重新渲染后也执行。

场景 2:依赖项为空数组 → 仅首次渲染执行

相当于类组件的 componentDidMount,适合只需要执行一次的操作(比如初始化请求、添加全局监听)。

import { useEffect } from 'react';

function UserList() {
  useEffect(() => {
    // 仅首次渲染时请求数据(只执行一次)
    const fetchUsers = async () => {
      const res = await fetch('https://api.example.com/users');
      const data = await res.json();
      console.log('用户数据:', data);
    };
    fetchUsers();

    // 清理函数:组件卸载时执行(比如取消请求)
    return () => {
      console.log('组件卸载,清理资源');
    };
  }, []); // 空依赖数组

  return <div>用户列表</div>;
}
执行时机:仅组件首次渲染完成后执行一次,清理函数在组件卸载时执行。

场景 3:依赖项数组包含特定值 → 仅依赖项变化时执行

相当于类组件的 componentDidUpdate(仅监听指定状态),是最常用的场景。

import { useState, useEffect } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  // 仅当userId变化时,重新请求用户信息
  useEffect(() => {
    const fetchUser = async () => {
      const res = await fetch(`https://api.example.com/users/${userId}`);
      const data = await res.json();
      setUser(data);
    };
    fetchUser();

    // 清理函数:下一次effect执行前/组件卸载时执行
    return () => {
      console.log(`停止请求userId: ${userId}的信息`);
    };
  }, [userId]); // 依赖项:userId

  if (!user) return <div>加载中...</div>;
  return <div>用户名:{user.name}</div>;
}
执行时机:首次渲染执行 + 每次 userId 变化时重新执行,清理函数会在 “下一次 effect 执行前” 先执行。

四、关键注意事项

1.清理函数的必要性:

比如定时器如果不清理,组件卸载后仍会执行,导致内存泄漏:

useEffect(() => {
  const timer = setInterval(() => {
    console.log('定时器执行');
  }, 1000);
  // 清理函数:清除定时器
  return () => clearInterval(timer);
}, []);

2.依赖项的正确性:

useEffect 内部用到的变量(如 state、props、函数)都必须加入依赖项数组,否则会捕获旧值(闭包问题)。
可以用 ESLint 规则 react-hooks/exhaustive-deps 自动检查依赖项是否完整。

3.effect 是同步的:

不要在 useEffect 外层加 async/await(会导致返回值变成 Promise,而非清理函数),正确写法是在内部定义异步函数:

// 错误写法
// useEffect(async () => { ... }, []); 
// 正确写法
useEffect(() => {
  const asyncFn = async () => { ... };
  asyncFn();
}, []);

总结

  • useEffect 是 React 函数组件处理副作用的核心 Hook,替代类组件的三个生命周期方法。
  • 依赖项数组决定执行时机:
    • 无数组 → 每次渲染执行;
    • 空数组 → 仅首次渲染执行;
    • 有值数组 → 依赖项变化时执行。
  • 清理函数用于释放资源(定时器、订阅、请求),避免内存泄漏,执行时机是 “组件卸载前” 或 “下一次 effect 执行前”
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容