React Hooks特性之useEffect解析

前言

在 React 的函数式组件开发中,useEffect 是一个极其重要的 Hook。它让我们能够在函数组件中处理副作用操作,如数据获取、订阅、手动 DOM 操作等。

React Hooks 基础回顾

在深入 useEffect 之前,我们先简单回顾一下 React Hooks 的基本概念。Hooks 是 React 16.8 引入的新特性,允许我们在不编写 class 组件的情况下使用 state 和其他 React 特性。

useEffect 是 Hooks 中最核心的一个,用于处理副作用操作。

useEffect深度解析

类型 示例 是否属于副作用
纯函数 const sum = (a, b) => a + b ❌ 无副作用
副作用操作 fetch(), setTimeout() ✅ 有副作用
状态更新 setState() ✅ 有副作用

基本概念

useEffect是React专门用于处理副作用的Hook,它能够:

  • 在组件渲染后执行副作用操作
  • 控制副作用的执行时机
  • 提供清理机制避免内存泄漏

副作用类型分析

执行机制详解

useEffect的执行可以分为三个阶段:

  1. ​挂载阶段​

    • 组件首次渲染后执行
    • 类似于类组件的componentDidMount
  2. ​更新阶段​

    • 依赖项变化时重新执行
    • 类似于类组件的componentDidUpdate
  3. ​卸载阶段​

    • 组件卸载时执行清理函数
    • 类似于类组件的componentWillUnmount

实战应用模式

模式一:持续执行的副作用

当不需要控制执行时机时,可以省略依赖数组:

jsx 复制代码
useEffect(() => {
  console.log('每次渲染后都会执行');
});

模式二:单次执行的副作用

通过空依赖数组控制只在挂载时执行:

jsx 复制代码
useEffect(() => {
  console.log('仅在组件挂载时执行');
  return () => {
    console.log('组件卸载时执行清理');
  };
}, []);

模式三:条件执行的副作用

通过指定依赖项控制执行时机:

jsx 复制代码
const [count, setCount] = useState(0);

useEffect(() => {
  console.log(`count变为: ${count}`);
  document.title = `当前计数: ${count}`;
}, [count]);

模式四:需要清理的副作用

当副作用涉及资源管理时,必须提供清理函数:

jsx 复制代码
useEffect(() => {
  const timer = setInterval(() => {
    console.log('定时器运行中');
  }, 1000);
  
  return () => {
    clearInterval(timer);
  };
}, []);

综合例子解析

下面通过一个完整的组件示例,展示useEffect的四种使用模式:

jsx 复制代码
import React, { useState, useEffect } from 'react';

function EffectDemo() {
  const [count, setCount] = useState(0);
  const [data, setData] = useState('初始数据');
  const [width, setWidth] = useState(window.innerWidth);

  // 模式1: 持续执行
  useEffect(() => {
    console.log('【模式1】每次渲染后执行');
  });

  // 模式2: 单次执行
  useEffect(() => {
    console.log('【模式2】组件挂载时执行');
    return () => {
      console.log('【模式2】组件卸载时清理');
    };
  }, []);

  // 模式3: 条件执行
  useEffect(() => {
    console.log(`【模式3】count变为: ${count}`);
    document.title = `当前计数: ${count}`;
    return () => {
      console.log('【模式3】清理前一次effect');
    };
  }, [count]);

  // 模式4: 需要清理
  useEffect(() => {
    console.log('【模式4】设置窗口监听器');
    const handleResize = () => {
      setWidth(window.innerWidth);
      console.log('窗口大小变化:', window.innerWidth);
    };
    window.addEventListener('resize', handleResize);
    
    return () => {
      console.log('【模式4】移除窗口监听器');
      window.removeEventListener('resize', handleResize);
    };
  }, []);

  return (
    <div style={{ padding: '20px', border: '1px solid #ccc' }}>
      <h2>useEffect四种模式示例</h2>
      {/* 各模式展示区域 */}
    </div>
  );
}

组件渲染流程分析

让我们分析一下组件在不同情况下的行为:

1. 组件首次挂载

  1. 执行所有useEffect钩子(按照声明顺序)

    • 模式1: 立即执行,控制台输出"【模式1】每次渲染后执行"
    • 模式2: 立即执行,控制台输出"【模式2】组件挂载时执行"
    • 模式3: 立即执行(因为count初始值变化被视为"变化"),控制台输出"【模式3】count变为: 0",设置文档标题
    • 模式4: 立即执行,控制台输出"【模式4】设置窗口监听器",添加resize事件监听器

2. 用户点击增加count按钮

  1. setCount触发状态更新

  2. 组件重新渲染

  3. 执行所有useEffect钩子:

  • 模式1: 再次执行,控制台输出"【模式1】每次渲染后执行"

  • 模式2: 不执行(依赖数组为空且不是首次渲染)

  • 模式3:

    先执行上一次effect的清理函数(如果有),控制台输出"【模式3】清理前一次effect",

    然后执行新的effect,控制台输出"【模式3】count变为: [新值]",更新文档标题。

  • 模式4: 不执行(依赖数组为空且不是首次渲染)

3. 调整浏览器窗口大小

  1. 浏览器触发resize事件

  2. 模式4中的handleResize函数被执行:

  • 更新width状态
  • 控制台输出"窗口大小变化: [新宽度]"
  1. 状态更新触发组件重新渲染

  2. 执行所有useEffect钩子:

  • 模式1: 再次执行,控制台输出"【模式1】每次渲染后执行"
  • 模式2: 不执行
  • 模式3: 不执行(count没有变化)
  • 模式4: 不执行(依赖数组为空且不是首次渲染)

4. 组件卸载

React调用所有effect的清理函数(按照与声明相反的顺序):

  • 模式4: 执行清理函数,控制台输出"【模式4】移除窗口监听器"
  • 模式3: 执行清理函数,控制台输出"【模式3】清理前一次effect"
  • 模式2: 执行清理函数,控制台输出"【模式2】组件卸载时清理"
  • 模式1: 没有清理函数,不执行任何操作
相关推荐
唐某人丶3 分钟前
教你如何用 JS 实现 Agent 系统(3)—— 借鉴 Cursor 的设计模式实现深度搜索
前端·人工智能·aigc
看到我请叫我铁锤8 分钟前
vue3使用leaflet的时候高亮显示省市区
前端·javascript·vue.js
南囝coding17 分钟前
Vercel 发布 AI Gateway 神器!可一键访问数百个模型,助力零门槛开发 AI 应用
前端·后端
AI大模型23 分钟前
前端学 AI 不用愁!手把手教你用 LangGraph 实现 ReAct 智能体(附完整流程 + 代码)
前端·llm·agent
小红40 分钟前
网络通信基石:从IP地址到子网划分的完整指南
前端·网络协议
一枚前端小能手44 分钟前
🔥 前端储存这点事 - 5个存储方案让你的数据管理更优雅
前端·javascript
willlzq1 小时前
深入探索Swift的Subscript机制和最佳实践
前端
RockerLau1 小时前
micro-zoe子应用路由路径污染问题
前端
代码代码快快显灵1 小时前
Axios的基本知识点以及vue的开发工程(基于大事件)详细解释
前端·javascript·vue.js
文心快码BaiduComate1 小时前
再获殊荣!文心快码荣膺2025年度优秀软件产品!
前端·后端·代码规范