当前位置: 首页 > news >正文

第八部分:第五节 - 生命周期与副作用 (`useEffect` Hook):组件的幕后工作

知识点: 组件生命周期(挂载 Mounting, 更新 Updating, 卸载 Unmounting - 高级概念),副作用 (Side Effects),useEffect Hook (用于处理副作用,如数据获取、订阅、DOM 操作),useEffect 的依赖数组,useEffect 的清理函数。

讲解:

React 组件有自己的“生命周期”,从被创建并添加到页面上(挂载),到数据或状态变化导致重新渲染(更新),再到从页面上移除(卸载)。在这些生命周期的不同阶段,我们可能需要执行一些“副作用”操作。

副作用 (Side Effects):

副作用是指在组件渲染过程中不是直接计算结果的操作。常见的副作用包括:

  • 数据获取 (Data Fetching): 从后端 API 请求数据。
  • 订阅 (Subscriptions): 建立 WebSocket 连接,监听事件等。
  • 手动修改 DOM: 直接操作浏览器 DOM (通常不推荐,除非必要)。
  • 定时器 (Timers): 设置 setTimeout 或 setInterval。
  • 日志记录 (Logging)。

这些操作不能直接放在组件函数体中(会无限循环或只执行一次),需要特殊的机制来管理。

useEffect Hook:

在功能组件中,我们使用 useEffect Hook 来处理副作用。useEffect 可以在组件渲染后执行代码。你可以把它想象成告诉 React:“在 DOM 更新后,帮我运行这段代码。”

useEffect 接收一个函数作为第一个参数,这个函数就包含了你要执行的副作用代码。

import React, { useState, useEffect } from 'react';function DataFetcher() {const [data, setData] = useState(null);const [isLoading, setIsLoading] = useState(true);// 使用 useEffect 处理数据获取副作用useEffect(() => {console.log('useEffect 运行了');// 在这里执行异步数据获取fetch('https://api.example.com/data') // 假设这是一个获取数据的 API.then(response => response.json()).then(data => {setData(data);setIsLoading(false);}).catch(error => {console.error('数据获取出错:', error);setIsLoading(false);});// useEffect 的默认行为是在每次渲染后都运行副作用函数// 这通常不是我们想要的,需要使用依赖数组控制执行时机}); // 没有依赖数组,每次渲染后都运行if (isLoading) {return <p>正在加载数据...</p>;}if (!data) {return <p>加载数据失败。</p>;}return (<div><h2>获取到的数据</h2><pre>{JSON.stringify(data, null, 2)}</pre></div>);
}

useEffect 的依赖数组 (Dependency Array):

useEffect 的第二个参数是一个依赖数组。它告诉 React 副作用应该在何时重新运行。

  • 没有依赖数组: 副作用在每次渲染后都运行。
  • 空数组 []: 副作用只在组件第一次挂载时运行一次 (componentDidMount 的替代)。适合执行一次性的设置或数据获取。
  • 包含变量的数组 [variable1, variable2]: 副作用在组件第一次挂载时运行一次,并且在依赖数组中的任何变量发生变化时重新运行。适合根据某些 State 或 Props 的变化来执行副作用。
// 只在组件挂载时获取一次数据 (空数组 [])
useEffect(() => {console.log('组件挂载,只运行一次');// 获取数据的代码...
}, []); // 空依赖数组// 当 userId 变化时重新获取数据
useEffect(() => {console.log('userId 或组件挂载时运行');if (userId) {// 根据新的 userId 获取用户详情fetch(`https://api.example.com/users/${userId}`).then(response => response.json()).then(userData => {// ... 更新用户 State});}
}, [userId]); // 依赖数组包含 userId// 没有依赖数组 (不推荐用于数据获取等异步操作,可能导致无限循环)
// useEffect(() => {
//   console.log('每次渲染后都运行');
// });

useEffect 的清理函数 (Cleanup Function):

有时候,副作用需要在组件卸载时下次副作用重新运行前进行清理,以避免内存泄漏或不必要的行为。比如清除定时器、取消订阅、关闭网络连接等。useEffect 可以选择返回一个函数,这个函数就是清理函数。

useEffect(() => {console.log('副作用设置');// 设置一个定时器const timerId = setInterval(() => {console.log('定时器运行中...');}, 1000);// 返回一个清理函数return () => {console.log('副作用清理');// 清除定时器clearInterval(timerId);};
}, []); // 空依赖数组,只在挂载时设置定时器,在卸载时清除

清理函数会在组件卸载时执行。如果 useEffect 因为依赖项变化而重新运行,清理函数会在新的副作用运行之前执行。

小结: useEffect Hook 是功能组件中处理副作用的核心工具。通过依赖数组可以控制副作用的执行时机(挂载时、更新时、特定依赖变化时)。返回清理函数可以处理副作用的清理工作,避免资源泄漏。理解 useEffect 是掌握在 React 中进行异步操作和与外部系统交互的关键。

练习:

  1. 在你的 my-restaurant-app 项目中,修改 MenuList 组件。
  2. 使用 useState 创建一个 State 变量 menuItemsisLoading (初始为 true)。
  3. 使用 useEffect Hook,在组件挂载时(空依赖数组),模拟从后端 API 获取菜单数据。你可以使用 setTimeout 延迟几秒来模拟网络请求。
  4. 在模拟请求成功后,更新 menuItems State,并将 isLoading 设置为 false。
  5. 在组件的 JSX 中,使用条件渲染:如果 isLoading 为 true,显示“菜单加载中…”,否则渲染菜单列表 (menuItems.map(...))。
  6. (进阶)创建一个新的组件 Timer.jsx。使用 useStateuseEffect 来创建一个简单的计时器,每秒更新并显示当前时间。在 useEffect 中设置 setInterval,并返回一个清理函数来清除定时器。

相关文章:

  • Java对象创建过程
  • Python-多线程(一)
  • Qwen3与MCP协议:重塑大气科学的智能研究范式
  • JSON基础知识
  • Java框架面试题
  • 【HarmonyOS 5】游戏开发教程
  • 国标GB28181视频平台EasyGBS视频实时监控系统打造换热站全景可视化管理方案
  • 第二章 2.2 数据存储安全风险之数据存储风险分析
  • Mac 双系统
  • 如何在 React 中监听 div 的滚动事件
  • 导出onnx的两种方法
  • 在本地查看服务器上的TensorBoard
  • 2025年- H65-Lc173--347.前k个高频元素(小根堆,堆顶元素是当前堆元素里面最小的)--Java版
  • 洛谷P1591阶乘数码
  • JavaWeb简介
  • 二维 根据矩阵变换计算镜像旋转角度
  • 【LLM大模型技术专题】「入门到精通系列教程」LangChain4j与Spring Boot集成开发实战指南
  • 记录一下centos8安装nginx并部署使用
  • 使用 Python 的 psutil 库进行系统资源监控
  • Apparent connection leak detected问题排查
  • 网站设计论文5000/自动友链网
  • 做网站啦代理的方法/如何发布视频赚钱
  • wordpress users/深圳外包seo
  • 网站后台管理员做链接/bt磁力链好用的引擎
  • 建设什么网站可以赚钱/友情链接买卖代理
  • 为什么大网站的百度快照更新速度慢还排第一/百度快照客服人工电话