是否有理由在 React 中保持状态完全不可变?
Is there a reason to keep state completely immutable in React?
以状态为例:
const [state, setState] = useState({ x: 1, nested: { y: 2, z: 3 } });
增加 y 值的处理程序的不可变版本如下:
function incrementY() {
setState((state) => {
return { ...state, nested: { ...state.nested, y: state.nested.y + 1 } };
});
}
下一个版本会创建一个新的状态对象,但会改变嵌套对象:
function incrementY() {
setState((state) => {
state.nested.y += 1;
return { ...state };
});
}
两个版本都会导致组件的重新渲染。现在,让我们假设这个组件呈现一个子组件:
return (
<div onClick={() => incrementY()}>
<Child nested={state.nested} />
</div>
);
如果我理解正确,父组件的重新渲染总是会导致子组件的重新渲染(即使对嵌套对象的引用保持不变)。
我知道不可变状态在需要保留状态历史时很有用(例如,对于 CTRL + Z 功能)。但是有没有我遗漏的特定于 React 的原因?
If I understand correctly, a re-render of the parent component will always lead to a re-render of the child component
默认情况下是,但是子组件可以使用 React.memo
(或 class 组件的其他技术)在其 props 没有改变的情况下跳过渲染。如果您改变嵌套对象,然后将该对象传递给子对象,它在子对象看来就像什么都没有改变一样。
所以如果你想能够可靠地使用 React 的工具来跳过渲染,那么你必须让你的状态在所有级别都是不可变的。
以状态为例:
const [state, setState] = useState({ x: 1, nested: { y: 2, z: 3 } });
增加 y 值的处理程序的不可变版本如下:
function incrementY() {
setState((state) => {
return { ...state, nested: { ...state.nested, y: state.nested.y + 1 } };
});
}
下一个版本会创建一个新的状态对象,但会改变嵌套对象:
function incrementY() {
setState((state) => {
state.nested.y += 1;
return { ...state };
});
}
两个版本都会导致组件的重新渲染。现在,让我们假设这个组件呈现一个子组件:
return (
<div onClick={() => incrementY()}>
<Child nested={state.nested} />
</div>
);
如果我理解正确,父组件的重新渲染总是会导致子组件的重新渲染(即使对嵌套对象的引用保持不变)。
我知道不可变状态在需要保留状态历史时很有用(例如,对于 CTRL + Z 功能)。但是有没有我遗漏的特定于 React 的原因?
If I understand correctly, a re-render of the parent component will always lead to a re-render of the child component
默认情况下是,但是子组件可以使用 React.memo
(或 class 组件的其他技术)在其 props 没有改变的情况下跳过渲染。如果您改变嵌套对象,然后将该对象传递给子对象,它在子对象看来就像什么都没有改变一样。
所以如果你想能够可靠地使用 React 的工具来跳过渲染,那么你必须让你的状态在所有级别都是不可变的。