React 19 入门教程
状态结构选择
本教程共 50 篇 · 第 20 篇 · 更新于 2026-07-29 · 约 7 分钟阅读
React状态结构状态设计冗余状态状态组织
20. 状态结构选择
本节目标:学会合理组织 state 结构,避免冗余和矛盾,让状态既简洁又不容易出错。
组织 state 有三个原则,记住就行:
合并相关状态
两个 state 总是一起变化,合并成一个:
// 不好:两个独立 state
const [x, setX] = useState(0);
const [y, setY] = useState(0);
// 好:合并成一个
const [position, setPosition] = useState({ x: 0, y: 0 });
// 更新时
setPosition({ x: 100, y: 200 });
什么时候合并
你发现两个 setState 总是一起调用,说明它们应该合并。
避免冗余状态
能算出来的值,不要存 state:
// 不好:fullName 是冗余的
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [fullName, setFullName] = useState('');
useEffect(() => {
setFullName(firstName + ' ' + lastName);
}, [firstName, lastName]);
// 好:直接计算
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const fullName = firstName + ' ' + lastName;
冗余状态的隐患
冗余 state 容易不同步。firstName 改了,fullName 可能忘了更新。
避免”镜像” props
不要把 props 复制成 state:
// 不好:把 props 复制成 state
function User({ user }) {
const [name, setName] = useState(user.name);
// props 变了,state 不会自动更新
}
// 好:直接用 props
function User({ user }) {
return <span>{user.name}</span>;
}
如果确实需要”可修改的副本”,用 key 重置组件,或者只在初始化时用 props 设 state。
避免矛盾状态
多个 state 可能互相矛盾时,合并成一个:
// 不好:status 和 isSending 可能矛盾
const [isSending, setIsSending] = useState(false);
const [isSent, setIsSent] = useState(false);
// 好:一个状态变量表示所有情况
const [status, setStatus] = useState('typing');
// 'typing' | 'sending' | 'sent'
function handleSend() {
setStatus('sending');
// 请求完成后
setStatus('sent');
}
避免重复状态
同一份数据不要存两份:
// 不好:items 和 itemCount 重复
const [items, setItems] = useState([]);
const [itemCount, setItemCount] = useState(0);
// 好:count 从 items 计算
const [items, setItems] = useState([]);
const itemCount = items.length;
避免过深嵌套
嵌套太深的 state 更新很痛苦:
// 不好:三层嵌套
const [form, setForm] = useState({
user: {
profile: {
address: { city: '' }
}
}
});
// 好:拆成多个独立 state
const [city, setCity] = useState('');
const [street, setStreet] = useState('');
嵌套太深怎么办
如果业务确实需要嵌套,考虑用 Immer 库简化更新。后面会讲。
实战:设计一个表单的 state
function CheckoutForm() {
// 表单字段:合并成一个对象
const [form, setForm] = useState({
name: '',
email: '',
address: ''
});
// 提交状态:一个变量表示所有情况
const [status, setStatus] = useState('idle');
// 'idle' | 'submitting' | 'success' | 'error'
// 错误信息:从 status 派生
const isSubmitting = status === 'submitting';
const canSubmit = form.name && form.email && !isSubmitting;
function updateField(field, value) {
setForm({ ...form, [field]: value });
}
return (
<form>
<input
value={form.name}
onChange={e => updateField('name', e.target.value)}
disabled={isSubmitting}
/>
<button disabled={!canSubmit}>
{isSubmitting ? '提交中...' : '提交'}
</button>
</form>
);
}
状态结构检查清单
设计 state 时问自己:
- 这个值能算出来吗?能算就别存
- 这两个 state 总是一起变吗?合并
- 这个值和另一个 state 会矛盾吗?合并
- 这个值是 props 的副本吗?直接用 props
- 嵌套超过两层了吗?考虑拆分
本节要点
- 相关状态合并,独立状态拆分
- 能计算的值不要存 state
- 一个状态变量表示多种情况,避免矛盾
- 嵌套太深考虑拆分或 Immer