为什么在反应中手动改变状态是一个反模式?



假设我有一个复杂的状态,其中包含复制成本很高的字段色调,我想按特定顺序更新。"supposedly"正确的方法可能是

setState({
...myComplexState,
expensiveFieldA: newA,
});
// some logic to compute newB
setState({
...myComplexState,
expensiveFieldB: newB,
});

这不仅会触发不必要的重新渲染,而且还会在处理未更改的字段时浪费cpu周期,使替代模式更具吸引力

import { useState } from 'react';
class StateWrapper<S> {
state: S;
constructor(state: S) {
this.state = state;
}
shallowCopy() {
return new StateWrapper(this.state);
}
}
function useObjState<T>(initState: T): [T, () => void] {
const [wrapper, setWrapper] = useState(() => new StateWrapper(initState));
const commit = () => setWrapper(wrapper.shallowCopy());
return [wrapper.state, commit];
}
class ExpensiveState {
private val: string;
constructor() {
this.val = '';
}
preformExpensiveOperations(val: string) {
this.val = val;
}
preformAnotherExpensiveOperation() {}
getVal() {
return this.val;
}
}
function App() {
const [state, commit] = useObjState(new ExpensiveState());
return (
<>
<p>val: {state.getVal()}</p>
<p>
<input
onChange={e => {
state.preformExpensiveOperations(e.target.value);
state.preformAnotherExpensiveOperation();
commit();
}}
/>
</p>
</>
);
}
export default App;

我知道这是反模式的,但是为什么不鼓励呢?

不鼓励这样做的最明显的原因是它违背了React的原则,该原则强调以清晰和声明的方式编写代码。

不太明显的原因是,虽然您的替代模式看起来可以工作,但它可能会导致意想不到的行为。如果有人在你离开很久之后还在调试你的代码,他们可能不知道解决问题的最佳方法。

因此,为了子孙后代,我们依赖setState,但如果你真的很看重性能,那么我建议使用Redux来处理复杂的状态。

最新更新