深入解析 React 的 useEffect:从入门到实战

news2025/5/19 2:55:02

文章目录

  • 前言
    • 一、为什么需要 `useEffect`?
      • 核心作用:
    • 二、`useEffect` 的基础用法
      • 1. 基本语法
      • 2. 依赖项数组的作用
    • 三、依赖项数组演示
      • 1. 空数组 `[]`:
      • 2.无依赖项(空)
      • 3.有依赖项
    • 四、清理副作用函数
      • 实战案例演示
      • 1. 清除定时器
      • 2. 取消网络请求
  • 总结


前言

在 React 函数组件中,useEffect 是处理副作用(Side Effects)的核心 Hook。无论是数据获取、订阅事件、手动操作 DOM,还是其他异步任务,useEffect 都能帮助开发者优雅地管理这些副作用。然而,它的使用场景复杂且容易踩坑。本文将带你从基础到实战,全面掌握 useEffect 的核心原理和最佳实践。


一、为什么需要 useEffect

在类组件中,副作用通常通过生命周期方法(如 componentDidMountcomponentDidUpdatecomponentWillUnmount)管理。但在函数组件中,由于没有生命周期方法,React 提供了 useEffect 来统一处理这些场景。

核心作用:

  1. 数据获取:在组件挂载后从 API 获取数据。
  2. 订阅/取消订阅:如 WebSocket、事件监听等。
  3. 手动操作 DOM:如调整滚动位置、聚焦输入框。
  4. 清理副作用:避免内存泄漏或重复操作。

二、useEffect 的基础用法

1. 基本语法

	import { useEffect } from 'react';
	function MyComponent() {
	  useEffect(() => {
	    // 副作用代码
	    return () => {
	      // 清理函数(可选)
	    };

	  }, [dependencies]); // 依赖项数组(可选) 
	  return <div>...</div>;

	}

2. 依赖项数组的作用

  • 空数组:只在组件挂载时执行一次(类似 componentDidMount)。
  • 无依赖项:每次组件渲染后都会执行(类似 componentDidUpdate,但容易引发性能问题)。
  • 有依赖项:当依赖项变化时重新执行。

三、依赖项数组演示

1. 空数组 []

只在组件挂载时执行一次(类似 componentDidMount)**

场景:组件挂载时执行一次初始化操作(如获取初始数据、订阅事件)。

	import { useState, useEffect } from 'react';
	function InitialDataLoader() {
	  const [data, setData] = useState(null);
	  useEffect(() => {
	    async function fetchInitialData() {
	      const response = await fetch('/api/initial-data');
	      const result = await response.json();
	      setData(result);
	    }
	    fetchInitialData();
	  }, []); // 空数组:仅在组件挂载时执行
	  if (!data) return <div>Loading initial data...</div>;
	  return <div>{JSON.stringify(data)}</div>;
	}
  • useEffect 仅在组件挂载时执行一次,适合初始化操作。
  • 清理函数(可选)通常用于取消订阅或清除资源(如 AbortController)。

2.无依赖项(空)

无依赖项:每次组件渲染后都会执行(类似 componentDidUpdate,但容易引发性能问题

场景:每次组件渲染后都执行某些操作(如记录日志、强制更新)。
注意:无依赖项的 useEffect 通常不推荐使用,除非明确需要每次渲染后执行。

	import { useEffect } from 'react';
	function LoggerComponent() {
	  useEffect(() => {
	    console.log('Component rendered or updated');
	  }); // 无依赖项:每次渲染后都会执行
	  return <div>Check the console for render logs.</div>;
	}
  • 每次组件渲染(包括状态更新、父组件更新等)后都会触发 useEffect
  • 慎用:可能导致性能问题(如无限循环、频繁 API 调用)。

3.有依赖项

:当依赖项变化时重新执行

场景:依赖项(如状态、props)变化时重新执行副作用(如数据更新、重新订阅)。

	import { useState, useEffect } from 'react';
	function UserData({ userId }) {
	  const [user, setUser] = useState(null);
	  useEffect(() => {
	    async function fetchUser() {
	      const response = await fetch(`/api/users/${userId}`);
	      const data = await response.json();
	      setUser(data);
	    }
	    fetchUser();
	  }, [userId]); // 依赖项:userId 变化时重新执行 
	  if (!user) return <div>Loading user data...</div>;
	  return <div>{user.name}</div>;
	}
	// 父组件使用示例
	function App() {
	  const [currentUserId, setCurrentUserId] = useState(1);
	  return (
	    <div>
	      <button onClick={() => setCurrentUserId(2)}>Load User 2</button>
	      <UserData userId={currentUserId} />
	    </div>
	  );
	}
  • userId 变化时(如点击按钮切换用户),useEffect 会重新执行,获取新用户数据。
  • 依赖项可以是状态、props 或其他变量,确保副作用与组件状态同步。

四、清理副作用函数

在 React 的 useEffect 中,清理副作用函数(cleanup function)用于在组件卸载或依赖项变化时清除之前的副作用(如取消订阅事件、清除定时器、关闭网络请求等)。以下是几个常见的清理副作用函数的示例:

import { useState, useEffect } from "react";

function Child() {
  useEffect(() => {
    console.log("child 初始化");
    return () => {
      console.log("child 卸载了");
    };
  });
  return <div>child</div>;
}
function App() {
  const [count, setCount] = useState(0);
  const [state, setState] = useState(true);
  useEffect(() => {
    return () => {
      console.log("我执行了!!!");
    };
  }, [count]);
  return (
    <>
      <div>
        <button onClick={() => setCount(count + 1)}>+1</button>
        <button onClick={() => setState(!state)}>显示/隐藏</button>
      </div>
      {state && <Child />}
    </>
  );
}

export default App;

在这里插入图片描述

实战案例演示

1. 清除定时器

场景:组件中使用了定时器,需要在组件卸载或依赖项变化时清除定时器。

	import { useState, useEffect } from 'react';
	function TimerComponent() {
	  const [count, setCount] = useState(0);
	  useEffect(() => {
	    const timer = setInterval(() => {
	      setCount((prev) => prev + 1);
	    }, 1000);
	    // 清理函数:清除定时器
	    return () => {
	      clearInterval(timer);
	    };
	  }, []); // 空数组:仅在组件挂载时设置定时;
	
	  return <div>Count: {count}</div>;
	}
  • 组件卸载时,clearInterval(timer) 会被调用,避免内存泄漏。

2. 取消网络请求

场景:组件中发起了网络请求,需要在组件卸载或依赖项变化时取消请求。

	import { useState, useEffect } from 'react';
	function DataFetcher({ userId }) {
	  const [data, setData] = useState(null);
	  useEffect(() => {
	    const abortController = new AbortController();
	    async function fetchData() {
	      try {
	        const response = await fetch(`/api/users/${userId}`, {
	          signal: abortController.signal,
	        });
	        const result = await response.json();
	        setData(result);
	      } catch (error) {
	        if (error.name !== 'AbortError') {
	          console.error('Fetch error:', error);
	        }
	      }
	    }
	    fetchData();
	    // 清理函数:取消请求
	    return () => {
	      abortController.abort();
	    };
	  }, [userId]); // 依赖项:userId 变化时重新执行
	  if (!data) return <div>Loading...</div>;
	  return <div>{JSON.stringify(data)}</div>;
	}

总结

useEffect 是 React 函数组件中管理副作用的强大工具,但需要开发者深入理解其工作原理和潜在问题。通过合理使用依赖项、清理函数和函数式更新,可以避免常见的陷阱,写出高效、稳定的代码。

希望本文能帮助你更好地掌握 useEffect,并在实际项目中灵活运用!如果有任何疑问或补充,欢迎在评论区留言讨论。 🚀

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2378962.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通过Ollama读取模型

通过Ollama读取模型 前言一、查看本地Ollama上有哪些模型二、调用bge-m3模型1、调用模型2、使用bge-m3进行相似度比较 三、调用大模型 前言 手动下载和加载大模型通常需要复杂的环境配置&#xff0c;而使用Ollama可以避免这一问题。本文将介绍如何调用Ollama上的模型。 一、查…

永久免费,特殊版本!

随着大家审美的不断提升&#xff0c;无论是社交平台的日常分享还是特定场景的图像展示&#xff0c;人们对图像质量的要求都日益严苛。为了呈现更完美的视觉效果&#xff0c;许多小伙伴都会对原始图像进行精细化的后期处理&#xff0c;其中复杂背景抠图、光影调整、色彩校正等专…

Canva 推出自有应用生成器以与 Bolt 和 Lovable 竞争

AI 目前是一个巨大的市场,每个人都想从中分一杯羹。 即使是 Canva,这个以拖放图形设计而闻名的流行设计平台,也在其 Canva Create 2025 活动中发布了自己版本的代码生成器,加入了 AI 竞赛。 但为什么一个以设计为先的平台会提供代码生成工具呢? 乍看之下,这似乎有些不…

Matrix-Game:键鼠实时控制、实时生成的游戏生成模型(论文代码详细解读)

1.简介 本文介绍了一种名为Matrix-Game的交互式世界基础模型&#xff0c;专门用于可控的游戏世界生成。 Matrix-Game通过一个两阶段的训练流程来实现&#xff1a;首先进行大规模无标签预训练以理解环境&#xff0c;然后进行动作标记训练以生成交互式视频。为此&#xff0c;研…

MySQL 5.7在CentOS 7.9系统下的安装(下)——给MySQL设置密码

新下载下来的MySQL&#xff0c;由于没有root密码&#xff0c;&#xff08;1&#xff09;所以如果我们希望登陆mysql&#xff0c;得给mysql的root账户设置密码&#xff0c;或者另一方面来说&#xff0c;&#xff08;2&#xff09;未来如果你忘记root密码了&#xff0c;也能通过这…

机器学习笔记2

5 TfidfVectorizer TF-IDF文本特征词的重要程度特征提取 (1) 算法 词频(Term Frequency, TF), 表示一个词在当前篇文章中的重要性 逆文档频率(Inverse Document Frequency, IDF), 反映了词在整个文档集合中的稀有程度 (2) API sklearn.feature_extraction.text.TfidfVector…

重排序模型解读 mxbai-rerank-base-v2 强大的重排序模型

mxbai-rerank-base-v2 强大的重排序模型 模型介绍benchmark综合评价安装 模型介绍 mxbai-rerank-base-v2 是 Mixedbread 提供的一个强大的重排序模型&#xff0c;旨在提高搜索相关性。该模型支持多语言&#xff0c;特别是在英语和中文方面表现出色。它还支持代码和 SQL 排序&a…

期望是什么:(无数次的均值,结合概率)21/6=3.5

https://seeing-theory.brown.edu/basic-probability/cn.html 期望是什么:(无数次的均值,结合概率)21/6=3.5 一、期望(数学概念) 在概率论和统计学中,**期望(Expectation)**是一个核心概念,用于描述随机变量的长期平均取值,反映随机变量取值的集中趋势。 (一…

uniapp-vue3项目中引入高德地图的天气展示

前言&#xff1a; uniapp-vue3项目中引入高德地图的天气展示 效果&#xff1a; 操作步骤&#xff1a; 1、页面上用定义我们的 当前天气信息&#xff1a;<view></view> 2、引入我们的map文件 <script setup>import amapFile from ../../libs/amap-wx.js …

lc42接雨水

1.原题 42. 接雨水 - 力扣&#xff08;LeetCode&#xff09; 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 2.题目解析 这一题是经常被考到的一道算法题&#xff0c;其中最简单最好用的方法就是双指…

通义千问-langchain使用构建(三)

目录 序言docker 部署xinference1WSL环境docker安装2拉取镜像运行容器3使用的界面 本地跑chatchat1rag踩坑2使用的界面2.1配置个前置条件然后对话2.2rag对话 结论 序言 在前两天的基础上&#xff0c;将xinference调整为wsl环境&#xff0c;docker部署。 然后langchain chatcha…

系统漏洞扫描服务:维护网络安全的关键与服务原理?

系统漏洞扫描服务是维护网络安全的关键措施&#xff0c;能够迅速发现系统中的潜在风险&#xff0c;有效预防可能的风险和损失。面对网络攻击手段的日益复杂化&#xff0c;这一服务的重要性日益显著。 服务原理 系统漏洞扫描服务犹如一名恪尽职守的安全守护者。它运用各类扫描…

【Redis】零碎知识点(易忘 / 易错)总结回顾

一、Redis 是一种基于键值对&#xff08;key-value&#xff09;的 NoSQL 数据库 二、Redis 会将所有数据都存放在内存中&#xff0c;所以它的读写性能非常惊人 Redis 还可以将内存的数据利用快照和日志的形式保存到硬盘上&#xff0c;这样在发生类似断电或者机器故障时&#xf…

基于three.js 全景图片或视频开源库Photo Sphere Viewer

Photo Sphere Viewer 是一个基于 JavaScript 的开源库&#xff0c;专门用于在网页上展示 360 全景图片或视频。它提供了丰富的交互功能&#xff0c;允许用户通过鼠标、触摸屏或陀螺仪来浏览全景内容&#xff0c;适用于旅游、房地产、虚拟现实、教育等多个领域。 主要特点 多种…

LangPDF: Empowering Your PDFs with Intelligent Language Processing

LangPDF: Empowering Your PDFs with Intelligent Language Processing Unlock Global Communication: AI-Powered PDF Translation and Beyond In an interconnected world, seamless multilingual document management is not just an advantage—it’s a necessity. LangP…

OpenVLA (2) 机器人环境和环境数据

文章目录 [TOC](文章目录) 前言1 BridgeData V21.1 概述1.2 硬件环境 2 数据集2.1 场景与结构2.2 数据结构2.2.1 images02.2.2 obs_dict.pkl2.2.3 policy_out.pkl 3 close question3.1 英伟达环境3.2 LIBERO 环境更适合仿真3.3 4090 运行问题 前言 按照笔者之前的行业经验, 数…

代码复现5——VLMaps

项目地址 1 Setup # 拉取VLMaps仓库,成功运行后会在主目录生成文件夹vlmapsgit clone https://github.com/vlmaps/vlmaps.git#通过 conda 创建虚拟环境conda create -n vlmaps python=3.8 -yconda activate vlmaps #激活环境cd vlmaps # 切换到项目文件下bash install.ba…

Ocean: Object-aware Anchor-free Tracking

领域&#xff1a;Object tracking It aims to infer the location of an arbitrary target in a video sequence, given only its location in the first frame 问题/现象&#xff1a; Anchor-based Siamese trackers have achieved remarkable advancements in accuracy, yet…

计算机网络(1)——概述

1.计算机网络基本概念 1.1 什么是计算机网络 计算机网络的产生背景 在计算机网络出现之前&#xff0c;计算机之间都是相互独立的&#xff0c;每台计算机只能访问自身存储的数据&#xff0c;无法与其他计算机进行数据交换和资源共享。这种独立的计算机系统存在诸多局限性&#…

刘家祎双剧收官见证蜕变,诠释多面人生

近期&#xff0c;两部风格迥异的剧集迎来收官时刻&#xff0c;而青年演员刘家祎在《我家的医生》与《无尽的尽头》中的精彩演绎&#xff0c;无疑成为观众热议的焦点。从温暖治愈的医疗日常到冷峻深刻的少年救赎&#xff0c;他以极具张力的表演&#xff0c;展现出令人惊叹的可塑…