在 React 开发中,状态管理是驱动组件交互和数据流的核心。随着项目复杂度的提升,开发者常常面临一个看似简单却至关重要的抉择:我该使用 useState
,还是 useReducer
?
同样是一个 注册表单 (字段:username
、email
、password
、confirmPassword
、acceptTerms
),用 useState
和 useReducer
各写一遍,方便直观对比。
用 useState
版本
jsx
import { useState } from 'react';
function RegisterFormUseState() {
const [username, setUsername] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [acceptTerms, setAcceptTerms] = useState(false);
const handleSubmit = (e) => {
e.preventDefault();
if (password !== confirmPassword) {
alert('两次密码不一致!');
return;
}
console.log({ username, email, password, acceptTerms });
resetForm();
};
const resetForm = () => {
setUsername('');
setEmail('');
setPassword('');
setConfirmPassword('');
setAcceptTerms(false);
};
return (
<form onSubmit={handleSubmit}>
<input value={username} onChange={(e) => setUsername(e.target.value)} placeholder="用户名" />
<input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="邮箱" />
<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="密码" />
<input type="password" value={confirmPassword} onChange={(e) => setConfirmPassword(e.target.value)} placeholder="确认密码" />
<label>
<input type="checkbox" checked={acceptTerms} onChange={(e) => setAcceptTerms(e.target.checked)} />
同意条款
</label>
<button type="submit">注册</button>
<button type="button" onClick={resetForm}>重置</button>
</form>
);
}
特点:
- 每个字段一个
useState
。 - 重置表单需要逐个清空。
- 字段多了会有很多重复 setter。
用 useReducer
版本
jsx
import { useReducer } from 'react';
const initialState = {
username: '',
email: '',
password: '',
confirmPassword: '',
acceptTerms: false,
};
function reducer(state, action) {
switch (action.type) {
case 'updateField':
return { ...state, [action.field]: action.value };
case 'reset':
return initialState;
default:
return state;
}
}
function RegisterFormUseReducer() {
const [state, dispatch] = useReducer(reducer, initialState);
const handleSubmit = (e) => {
e.preventDefault();
if (state.password !== state.confirmPassword) {
alert('两次密码不一致!');
return;
}
console.log(state);
dispatch({ type: 'reset' });
};
return (
<form onSubmit={handleSubmit}>
<input
value={state.username}
onChange={(e) => dispatch({ type: 'updateField', field: 'username', value: e.target.value })}
placeholder="用户名"
/>
<input
value={state.email}
onChange={(e) => dispatch({ type: 'updateField', field: 'email', value: e.target.value })}
placeholder="邮箱"
/>
<input
type="password"
value={state.password}
onChange={(e) => dispatch({ type: 'updateField', field: 'password', value: e.target.value })}
placeholder="密码"
/>
<input
type="password"
value={state.confirmPassword}
onChange={(e) => dispatch({ type: 'updateField', field: 'confirmPassword', value: e.target.value })}
placeholder="确认密码"
/>
<label>
<input
type="checkbox"
checked={state.acceptTerms}
onChange={(e) => dispatch({ type: 'updateField', field: 'acceptTerms', value: e.target.checked })}
/>
同意条款
</label>
<button type="submit">注册</button>
<button type="button" onClick={() => dispatch({ type: 'reset' })}>重置</button>
</form>
);
}
特点:
- 所有字段集中管理在
state
。 - 重置、动态字段处理方便。
- 更新逻辑统一在
reducer
,可维护性高。
总结 : 为什么要用 useReducer
?
- 当你有多个状态值 要管理,且它们之间有关联(比如同时更新多个字段)
- 当更新逻辑复杂,用
useState
会很混乱 - 想让状态更新逻辑更清晰、集中、可测试