验证渲染过程中是否无条件设置状态,否则可能会触发额外的渲染并可能导致无限渲染循环。
¥Validates against unconditionally setting state during render, which can trigger additional renders and potential infinite render loops.
规则详情
¥Rule Details
在渲染过程中调用 setState
会在当前渲染完成之前无条件触发另一次渲染。这会创建一个无限循环,导致你的应用崩溃。
¥Calling setState
during render unconditionally triggers another render before the current one finishes. This creates an infinite loop that crashes your app.
常见违规
¥Common Violations
无效
¥Invalid
// ❌ Unconditional setState directly in render
function Component({value}) {
const [count, setCount] = useState(0);
setCount(value); // Infinite loop!
return <div>{count}</div>;
}
有效
¥Valid
// ✅ Derive during render
function Component({items}) {
const sorted = [...items].sort(); // Just calculate it in render
return <ul>{sorted.map(/*...*/)}</ul>;
}
// ✅ Set state in event handler
function Component() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
{count}
</button>
);
}
// ✅ Derive from props instead of setting state
function Component({user}) {
const name = user?.name || '';
const email = user?.email || '';
return <div>{name}</div>;
}
// ✅ Conditionally derive state from props and state from previous renders
function Component({ items }) {
const [isReverse, setIsReverse] = useState(false);
const [selection, setSelection] = useState(null);
const [prevItems, setPrevItems] = useState(items);
if (items !== prevItems) { // This condition makes it valid
setPrevItems(items);
setSelection(null);
}
// ...
}
故障排除
¥Troubleshooting
我想将状态同步到属性
¥I want to sync state to a prop
一个常见问题是尝试在渲染后获取 “fix” 状态。假设你想防止计数器超过 max
prop:
¥A common problem is trying to “fix” state after it renders. Suppose you want to keep a counter from exceeding a max
prop:
// ❌ Wrong: clamps during render
function Counter({max}) {
const [count, setCount] = useState(0);
if (count > max) {
setCount(max);
}
return (
<button onClick={() => setCount(count + 1)}>
{count}
</button>
);
}
一旦 count
超过 max
,就会触发无限循环。
¥As soon as count
exceeds max
, an infinite loop is triggered.
相反,通常最好将此逻辑移至事件(首次设置状态的地方)。例如,你可以在更新状态时强制执行最大值:
¥Instead, it’s often better to move this logic to the event (the place where the state is first set). For example, you can enforce the maximum at the moment you update state:
// ✅ Clamp when updating
function Counter({max}) {
const [count, setCount] = useState(0);
const increment = () => {
setCount(current => Math.min(current + 1, max));
};
return <button onClick={increment}>{count}</button>;
}
现在,setter 仅在点击时运行,React 正常完成渲染,并且 count
永远不会与 max
重叠。
¥Now the setter only runs in response to the click, React finishes the render normally, and count
never crosses max
.
在极少数情况下,你可能需要根据之前渲染的信息调整状态。对于这些,请遵循 这个模式 的条件设置状态。
¥In rare cases, you may need to adjust state based on information from previous renders. For those, follow this pattern of setting state conditionally.