news 2026/6/10 17:03:17

react组件(2)---State 与生命周期

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
react组件(2)---State 与生命周期

1. 什么是 React State?

State(状态)是 React 组件中存储可变数据的容器,它决定了组件的行为和渲染输出。与 Props 不同,State 是组件内部管理且可以变化的,而 Props 是从父组件传递过来的只读属性。

State 的核心特征包括:

  • 可变性:State 可以在组件生命周期内发生变化

  • 响应式:State 的改变会自动触发组件的重新渲染

  • 局部性:State 是组件私有的,其他组件无法直接访问

  • 异步性:setState 操作可能是异步的,React 会批量处理状态更新

在 React 中,将组件视为一个状态机,通过管理状态的变化来驱动 UI 的更新。

2. 类组件中的 State

2.1 状态的声明与初始化

在类组件中,State 通常在构造函数中初始化:

class Counter extends React.Component { constructor(props) { super(props); this.state = { count: 0, isActive: false }; } }

现代写法也可以使用类属性语法:

class Counter extends React.Component { state = { count: 0, isActive: false }; }

2.2 状态的更新

更新 State 必须使用setState()方法,绝对不能直接修改 state

// 错误做法 this.state.count = 1; // 不会触发重新渲染! // 正确做法 this.setState({ count: 1 }); // 当新状态依赖于旧状态时,使用函数形式 this.setState(prevState => ({ count: prevState.count + 1 }));

3. 函数组件中的 State(useState Hook)

React 16.8 引入了 Hooks,允许函数组件使用 State。useState是最基础的 Hook。

3.1 useState 的基本用法

import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); return ( <div> <p>当前计数:{count}</p> <button onClick={() => setCount(count + 1)}> 点击增加 </button> </div> ); }

3.2 useState 的高级用法

函数式更新(当新状态依赖于旧状态时):

const [count, setCount] = useState(0); // 推荐:使用函数式更新确保基于最新状态 const increment = () => { setCount(prevCount => prevCount + 1); };

延迟初始化(当初始状态需要复杂计算时):

const [state, setState] = useState(() => { const expensiveValue = performExpensiveCalculation(); return expensiveValue; });

对象和数组的状态管理

// 对象状态更新 const [user, setUser] = useState({ name: 'Alice', age: 25 }); setUser(prevUser => ({ ...prevUser, name: 'Bob' })); // 数组状态更新 const [items, setItems] = useState(['apple', 'banana']); setItems(prevItems => [...prevItems, 'orange']);

4. React 组件生命周期

类组件生命周期函数组件 useEffect 实现方式
componentDidMountuseEffect (() => {}, [])(空依赖数组)
componentDidUpdateuseEffect (() => {}, [deps])(依赖项变化时执行)
componentWillUnmountuseEffect (() => { return () => {} }, [])(返回清理函数)

4.1 生命周期概述

React 组件的生命周期可以分为三个主要阶段:

  • 挂载阶段:组件被创建并插入 DOM

  • 更新阶段:组件的 props 或 state 发生变化时重新渲染

  • 卸载阶段:组件从 DOM 中移除

4.2 类组件的生命周期方法

挂载阶段

  • constructor():初始化 state 和绑定方法

  • static getDerivedStateFromProps():在渲染前根据 props 更新 state

  • render():渲染组件(必需方法)

  • componentDidMount():组件挂载后执行,适合进行数据获取、订阅等副作用操作

更新阶段

  • static getDerivedStateFromProps():更新前根据 props 调整 state

  • shouldComponentUpdate():决定组件是否应该更新(性能优化关键)

  • render():重新渲染组件

  • getSnapshotBeforeUpdate():在 DOM 更新前捕获一些信息

  • componentDidUpdate():组件更新后执行,可以操作 DOM 或执行网络请求

卸载阶段

  • componentWillUnmount():组件卸载前执行清理操作,如取消定时器、网络请求等

4.3 函数组件中的"生命周期"(useEffect Hook)

useEffectHook 在函数组件中承担了生命周期方法的职责:

import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // 相当于 componentDidMount + componentDidUpdate useEffect(() => { document.title = `点击了 ${count} 次`; }); // 只在挂载时执行(类似 componentDidMount) useEffect(() => { console.log('组件挂载完成'); }, []); // 依赖变化时执行(类似 componentDidUpdate) useEffect(() => { console.log(`count 变为: ${count}`); }, [count]); // 清理效果(类似 componentWillUnmount) useEffect(() => { const timer = setInterval(() => { // 一些操作 }, 1000); return () => { clearInterval(timer); // 清理函数 }; }, []); return ( <div> <p>你点击了 {count} 次</p> <button onClick={() => setCount(count + 1)}> 点击我 </button> </div> ); }

5. State 设计的最佳实践

5.1 State 的最小化原则

只将真正需要响应式更新的数据放入 State,派生数据可以在渲染时计算:

// 不好的做法:将派生数据放入 State state = { items: [], totalCount: 0, // 可以从 items.length 派生 filteredItems: [] // 可以从 items 过滤得到 }; // 好的做法:只存储原始数据 state = { items: [] }; // 派生数据在 render 中计算 get totalCount() { return this.state.items.length; }

5.2 State 结构的扁平化

避免嵌套过深的 State 结构:

// 不好的嵌套结构 state = { user: { profile: { personalInfo: { name: '', age: 0 } } } }; // 好的扁平结构 state = { userName: '', userAge: 0 };

5.3 不可变更新模式

始终使用不可变的方式更新 State:

// 数组更新 // 错误:直接修改原数组 this.state.items.push(newItem); // 正确:创建新数组 this.setState({ items: [...this.state.items, newItem] }); // 对象更新 // 错误:直接修改原对象 this.state.user.name = 'New Name'; // 正确:创建新对象 this.setState({ user: { ...this.state.user, name: 'New Name' } });

6. 常见场景与实战示例

6.1 数据获取场景

class DataFetcher extends React.Component { state = { data: [], loading: true, error: null, page: 1 }; componentDidMount() { this.fetchData(); } componentDidUpdate(prevProps, prevState) { if (prevState.page !== this.state.page) { this.fetchData(); } } fetchData = async () => { try { this.setState({ loading: true, error: null }); const response = await fetch(`/api/data?page=${this.state.page}`); const result = await response.json(); this.setState({ data: result, loading: false }); } catch (error) { this.setState({ error: error.message, loading: false }); } }; render() { const { data, loading, error, page } = this.state; if (loading) return <div>加载中...</div>; if (error) return <div>错误: {error}</div>; return ( <div> {/* 渲染数据 */} </div> ); } }

6.2 表单处理场景

function ContactForm() { const [formData, setFormData] = useState({ name: '', email: '', message: '' }); const handleChange = (e) => { const { name, value } = e.target; setFormData(prev => ({ ...prev, [name]: value })); }; const handleSubmit = (e) => { e.preventDefault(); // 提交表单数据 }; return ( <form onSubmit={handleSubmit}> <input name="name" value={formData.name} onChange={handleChange} /> <input name="email" value={formData.email} onChange={handleChange} /> <textarea name="message" value={formData.message} onChange={handleChange} /> <button type="submit">提交</button> </form> ); }

7. 常见陷阱与解决方案

7.1 过时状态问题

在闭包中捕获过时状态值:

// 问题代码:可能捕获过时状态 const [count, setCount] = useState(0); const increment = () => { setTimeout(() => { setCount(count + 1); // 可能使用过时的 count 值 }, 3000); }; // 解决方案:使用函数式更新 const increment = () => { setTimeout(() => { setCount(prevCount => prevCount + 1); // 总是基于最新状态 }, 3000); };

7.2 useEffect 的依赖数组

正确处理 useEffect 的依赖数组避免无限循环:

// 错误:缺少依赖可能导致过时数据 useEffect(() => { fetchData(userId); }, []); // 错误:依赖不完整可能导致意外行为 useEffect(() => { fetchData(userId); }, [userId]); // 如果 fetchData 使用了其他状态,需要包含 // 正确:包含所有依赖 useEffect(() => { fetchData(userId); }, [userId, fetchData]); // 如果 fetchData 在渲染中定义,需要用 useCallback 包装

8. 总结

React 的 State 和生命周期是构建交互式界面的核心概念。无论是类组件还是函数组件,合理管理状态和理解组件生命周期都是开发高质量 React 应用的关键。

主要要点回顾

  • State 是组件内部的可变数据,Props 是从外部传入的只读数据

  • 类组件使用this.statethis.setState(),函数组件使用useStateHook

  • 生命周期方法让你在组件不同阶段执行代码,useEffect在函数组件中承担类似职责

  • 遵循 State 设计最佳实践(最小化、扁平化、不可变更新)

  • 注意常见陷阱,如过时状态和 useEffect 的依赖处理

随着 React 的发展,函数组件和 Hooks 已成为主流,但理解类组件的生命周期对于维护现有项目和深入理解 React 原理仍然很有价值。

希望本篇博客能帮助你更好地理解和应用 React 的 State 与生命周期概念!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 13:57:42

SAP-MR21和MR22的应用

在企业的物料管理与财务核算过程中&#xff0c;准确掌握库存的价值至关重要。SAP系统提供了多种工具来帮助企业维护和调整物料价格&#xff0c;其中 MR21 和 MR22 是两个常用且容易混淆的事务代码。MR21主要用于直接调整物料的标准价格&#xff0c;而MR22则用于在特殊情况下对库…

作者头像 李华
网站建设 2026/6/9 21:18:10

EmotiVoice语音合成语音指纹添加技术:防止滥用追踪溯源

EmotiVoice语音合成中的语音指纹技术&#xff1a;构建可信AI语音生态 在深度伪造&#xff08;Deepfake&#xff09;音频事件频发的今天&#xff0c;一段几可乱真的AI语音可能足以引发一场舆论风暴&#xff0c;甚至造成财产损失。2023年某地就曾出现不法分子利用克隆声音冒充企业…

作者头像 李华
网站建设 2026/6/10 14:00:09

bilibili-api-python终极指南:从零开始掌握B站数据分析

bilibili-api-python终极指南&#xff1a;从零开始掌握B站数据分析 【免费下载链接】bilibili-api 哔哩哔哩常用API调用。支持视频、番剧、用户、频道、音频等功能。原仓库地址&#xff1a;https://github.com/MoyuScript/bilibili-api 项目地址: https://gitcode.com/gh_mir…

作者头像 李华
网站建设 2026/6/10 13:59:59

Win10丢失msvcr110.dll怎么办?这里有修复办法

当你在Windows 10上尝试运行某个软件或游戏时&#xff0c;突然弹出“无法启动此程序&#xff0c;因为计算机中丢失msvcr110.dll”的错误窗口&#xff0c;这确实是一个常见且恼人的问题。这个dll文件是Microsoft Visual C Redistributable运行时库的一部分&#xff0c;许多应用程…

作者头像 李华
网站建设 2026/6/9 14:29:25

两台电脑怎么并行计算?这些方法和问题你要知道

将两台或多台电脑连接起来协同工作&#xff0c;提升整体计算能力&#xff0c;这种做法通常被称为集群计算或并行计算。它不再是大型科研机构的专利&#xff0c;随着硬件成本下降和开源工具普及&#xff0c;中小型团队甚至技术爱好者也开始尝试搭建自己的并行计算系统&#xff0…

作者头像 李华
网站建设 2026/6/10 13:59:50

网页动画Canvas粒子爆炸效果,实现方法与关键参数全解析

在网页动画与交互设计领域&#xff0c;Canvas粒子爆炸效果是一种极具视觉冲击力和表现力的技术。它通过程序生成大量粒子&#xff0c;并模拟物理运动&#xff0c;创造出如烟花、消散、汇聚等多种动态视觉效果。这项技术不仅是前端编程能力的体现&#xff0c;更是提升用户体验、…

作者头像 李华