验证渲染过程中是否无条件设置状态,否则可能会触发额外的渲染并可能导致无限渲染循环。
🌐 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
一个常见的问题是在渲染后尝试“修复”状态。假设你想防止计数器超过 max 属性:
🌐 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.