React 状态管理工具:setState(用于类组件)和 useState Hook(用于函数组件)对比
·
文章目录
详细讲解 React 中两个最重要的状态管理工具:
setState(用于类组件)和 useState Hook(用于函数组件)。
我会从概念、用法、异同点和最佳实践几个方面来阐述。
1. this.setState (用于类组件)
setState 是类组件中用于更新组件局部状态的方法。状态(state)是一个对象,存储着组件内部可能变化的数据。
基本用法
import React, { Component } from 'react';
class CounterClass extends Component {
// 1. 在构造函数中初始化 state
constructor(props) {
super(props);
this.state = {
count: 0
};
}
// 也可以使用类属性简化初始化(需要 Babel 支持)
// state = {
// count: 0
// };
increment = () => {
// 2. 使用 setState 更新状态
// 用法一:传入一个对象,它会浅合并到当前 state
this.setState({ count: this.state.count + 1 });
// 用法二:传入一个 updater 函数,用于依赖前一个状态
// this.setState((prevState, prevProps) => {
// return { count: prevState.count + 1 };
// });
};
render() {
return (
<div>
<p>You clicked {this.state.count} times (Class)</p>
<button onClick={this.increment}>Click me</button>
</div>
);
}
}
export default CounterClass;
重要特性
- 异步性:
setState是异步的。React 会将多个setState调用合并(Batching)在一起以提高性能,然后再进行一次重新渲染。这意味着你在调用setState后立即读取this.state,得到的可能不是更新后的值。 - 函数式更新:当新状态依赖于前一个状态时(如计数器),必须使用函数形式 (
this.setState((prevState) => {...})) 来保证你使用的是最新的 state。 - 回调函数:
setState接受第二个参数,它是一个可选的回调函数,会在状态更新完毕且组件重新渲染后执行。this.setState({ count: 10 }, () => { console.log('State has been updated and component re-rendered:', this.state.count); }); - 浅合并:当你传入一个对象时,
setState会将它浅合并到当前的 state。你不需要担心会覆盖整个 state 对象。
2. useState Hook (用于函数组件)
useState 是 React 16.8 引入的 Hook,它让你在函数组件中添加状态。
基本用法
import React, { useState } from 'react';
function CounterFunction() {
// 1. 调用 useState Hook 来声明一个状态变量。
// 它返回一个数组: [当前的状态值, 一个用于更新它的函数]
// useState 的参数是状态的初始值
const [count, setCount] = useState(0);
const increment = () => {
// 2. 使用 setter 函数更新状态
// 用法一:直接传入新的值
setCount(count + 1);
// 用法二:传入一个 updater 函数,用于依赖前一个状态
// setCount(prevCount => prevCount + 1);
};
return (
<div>
<p>You clicked {count} times (Function)</p>
<button onClick={increment}>Click me</button>
</div>
);
}
export default CounterFunction;
重要特性
- 异步性:由
useState返回的 setter 函数(如setCount)也是异步的。它们也会被 React 批量处理以优化性能。 - 函数式更新:与
setState一样,当新状态依赖于旧状态时,必须使用函数形式 (setCount(prevCount => prevCount + 1))。 - 直接替换 vs 合并:
useState的 setter 函数不会自动合并对象。如果你的状态是一个对象,你需要手动合并它。const [user, setUser] = useState({ name: 'John', age: 30 }); // 错误:这会覆盖整个 state,只留下 `age`,`name` 会丢失! // setUser({ age: 31 }); // 正确:使用展开运算符 (...) 先复制原有属性,再覆盖更新的属性 setUser(prevUser => ({ ...prevUser, age: 31 })); - 多个状态:你可以在一个组件中多次使用
useState来管理不同的状态变量。这是推荐的做法,而不是像类组件那样把所有状态放在一个大对象里。
3. 核心异同点对比
| 特性 | Class 组件 setState |
Function 组件 useState |
|---|---|---|
| 声明状态 | 在构造函数或类属性中初始化一个 state 对象 |
调用 useState Hook,返回状态变量和 setter 函数 |
| 更新状态 | this.setState(newStateOrUpdaterFn) |
setState(newValueOrUpdaterFn) |
| 状态类型 | 通常是一个对象 | 可以是任何类型(数字、字符串、对象、数组等) |
| 合并行为 | 自动浅合并对象 | 不自动合并,需要手动合并(使用展开运算符) |
| 获取最新状态 | 使用回调函数作为 setState 的第二个参数 |
使用 useEffect Hook 来响应状态变化 |
| 异步性 | 异步,会批量处理 | 异步,会批量处理 |
| 函数式更新 | this.setState((prevState) => newState) |
setState(prevValue => newValue) |
4. 如何选择?最佳实践
- 使用函数组件和 Hooks:对于新项目和新组件,强烈推荐使用函数组件和
useStateHook。这是 React 现在的标准和未来发展方向。它代码更简洁,逻辑更复用。 - 使用函数式更新:只要新状态依赖于旧状态,就一定要使用函数式更新。这是避免因异步更新导致 bug 的最重要规则。
// ✅ 正确且安全 setCount(prevCount => prevCount + 1); // ❌ 在某些情况下可能不安全(例如多次快速点击) setCount(count + 1); - 处理对象和数组:使用
useState更新对象或数组时,记得创建新的引用(使用展开运算符...或Array.prototype.map/filter等),以遵循不可变原则,确保 React 能正确检测到变化并触发重新渲染。 - 状态结构:在函数组件中,如果状态彼此独立, prefer 使用多个
useState调用,而不是把它们塞进一个对象里。这样逻辑更清晰。但如果状态总是一起变化,将它们放在一个对象里也是合理的。
总结
| 方面 | this.setState (Class) |
useState (Function) |
|---|---|---|
| 范式 | 面向对象 | 函数式 |
| 状态组织 | 单一 state 对象 | 多个独立的 state 变量 |
| 更新方式 | 合并更新 | 替换更新(需手动合并) |
| 现代性 | 传统方式,仍在支持 | 现代标准,推荐使用 |
更多推荐


所有评论(0)