useState 是 React Hooks 中最基础也是最常用的 Hook,它允许你在函数组件中添加本地状态(state),而无需使用类组件。
1. 基本语法
const [state, setState] = useState(initialState);
state: 当前的状态值。setState: 一个函数,用于更新状态。调用它会导致组件重新渲染。initialState: 状态的初始值。可以是任何值(数字、字符串、对象、数组等)。
2. 基本使用示例
示例 1:计数器(数字状态)
import React, { useState } from 'react';
function Counter() {
// 声明一个名为 "count" 的 state 变量,初始值为 0
const [count, setCount] = useState(0);
return (
<div>
<p>你点击了 {count} 次</p>
{/* 点击按钮时调用 setCount,将 count 加 1 */}
<button onClick={() => setCount(count + 1)}>
点我增加
</button>
{/* 另一种写法:传入一个函数,接收前一个状态值 */}
<button onClick={() => setCount(prevCount => prevCount + 1)}>
用函数形式增加
</button>
</div>
);
}
示例 2:开关(布尔值状态)
function Toggle() {
const [isOn, setIsOn] = useState(false);
return (
<div>
{/* 根据 isOn 的值显示不同的文本和样式 */}
<div className={`toggle ${isOn ? 'on' : 'off'}`}>
{isOn ? 'ON' : 'OFF'}
</div>
<button onClick={() => setIsOn(!isOn)}>
切换
</button>
</div>
);
}
示例 3:输入框(字符串状态)
function NameInput() {
const [name, setName] = useState('');
return (
<div>
<input
type="text"
value={name} // 受控组件:value 由 state 控制
onChange={(e) => setName(e.target.value)} // 更新 state
placeholder="请输入你的名字"
/>
<p>你好, {name || '陌生人'}!</p>
</div>
);
}
3. 使用对象或数组作为状态
当状态是一个对象或数组时,必须注意不可变性(Immutability)。不要直接修改状态,而是创建一个新对象/数组。
示例 4:用户信息(对象状态)
function UserProfile() {
const [user, setUser] = useState({
name: '',
age: 0,
email: ''
});
const handleChange = (e) => {
const { name, value } = e.target;
// ✅ 正确:创建新对象,使用展开操作符
setUser(prevUser => ({
...prevUser,
[name]: value
}));
};
return (
<form>
<input
name="name"
value={user.name}
onChange={handleChange}
placeholder="姓名"
/>
<input
name="age"
type="number"
value={user.age}
onChange={handleChange}
placeholder="年龄"
/>
<input
name="email"
value={user.email}
onChange={handleChange}
placeholder="邮箱"
/>
<pre>{JSON.stringify(user, null, 2)}</pre>
</form>
);
}
示例 5:待办事项列表(数组状态)
function TodoList() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const addTodo = () => {
if (input.trim() !== '') {
// ✅ 正确:创建新数组,使用展开操作符
setTodos(prevTodos => [
...prevTodos,
{ id: Date.now(), text: input, completed: false }
]);
setInput(''); // 清空输入框
}
};
const toggleTodo = (id) => {
setTodos(prevTodos =>
prevTodos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
);
};
return (
<div>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && addTodo()}
placeholder="添加新任务"
/>
<button onClick={addTodo}>添加</button>
<ul>
{todos.map(todo => (
<li
key={todo.id}
style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
onClick={() => toggleTodo(todo.id)}
>
{todo.text}
</li>
))}
</ul>
</div>
);
}
4. useState 的重要特性
| 特性 | 说明 |
|---|---|
| 惰性初始化 | 如果初始状态是通过复杂计算得到的,可以传入一个函数:useState(() => computeExpensiveValue())。该函数只在首次渲染时执行。 |
| 函数式更新 | 当新状态依赖于前一个状态时,使用 setState(prevState => newState) 形式,可以避免闭包问题。 |
| 批量更新 | 在事件处理函数中,多次 setState 调用可能会被合并(批处理),以提高性能。 |
| 触发重新渲染 | 每次调用 setState,即使新旧值相等(对于基础类型),也会触发组件重新渲染(但 React 会对虚拟 DOM 进行优化)。 |
总结
useState 是 React 函数组件的“状态引擎”:
- 声明状态:使用
const [state, setState] = useState(initialValue)。 - 读取状态:直接使用
state变量。 - 更新状态:调用
setState(newValue)或setState(prev => newValue)。 - 遵守不可变性:更新对象或数组时,创建新实例,不要直接修改。
它是构建交互式 React 应用的基础,结合 useEffect 等其他 Hooks,可以实现类组件的所有功能,且代码通常更简洁、更易于理解。
THE END


