
规则:set-state-in-render
ReactAPI 参考:ESLint 插件
规则:set-state-in-render
校验避免在渲染期间无条件设置 state,这可能会触发额外的渲染和潜在的无尽渲染循环。
规则详情
在渲染期间无条件调用 setState 会在当前渲染完成之前触发另一次渲染。这会创建一个无限循环,导致应用崩溃。
常见违规
无效
-
js
// ❌ Unconditional setState directly in render
function Component({value}) {
const [count, setCount] = useState(0);
setCount(value); // Infinite loop!
return <div>{count}</div>;
}
有效
js
// ✅ 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);
}
// ...
}
故障排查
我想将 state 同步到 prop
一个常见的问题是试图在 state 渲染后“修复”它。假设你想让计数器不超过 max prop:
js
// ❌ 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,就会触发无限循环。
相反,通常最好将此逻辑移至事件(state 首次被设置的地方)。例如,你可以在更新 state 时强制执行最大值:
js
// ✅ 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。
在极少数情况下,你可能需要根据先前渲染的信息调整 state。对于这些情况,请遵循 此模式 有条件地设置 state。
帮助我们改进文档
发现翻译问题或内容错误?请告诉我们。
