在updater function 中不能使用“任何”副作用。它可能会影响渲染过程,具体取决于具体的副作用。
不适合 React 原则(关注点分离,声明性代码)。
(我记得看到过一些特殊的用例,其中将一些代码放入更新程序函数是唯一的解决方案,但我不记得它是什么了。
通过重构代码可能还有更好的解决方案。)
1。使用副作用的后果
不能使用 ANY 副作用,原因与您不应在 useEffect 之外的任何其他地方使用副作用的原因相同。
某些副作用可能会影响渲染过程,其他副作用可能会正常工作(技术上),但您不不应该依赖 setter 函数中发生的事情 .
反应保证,例如如果您致电setState( prev => prev + 1 ),那么state 现在将比以前多一个。
React 不保证为了实现该目标会在幕后发生什么。 React 可能会以任意顺序多次调用这些 setter 函数,或者根本不调用。
示例
例如在这段代码中,您会期望 A 和 B 始终相同,但它可能会给您意外结果,例如 B 增加 2 而不是 1(例如,在 DEV 模式下和strict mode):
export function DoSideEffect(){
const [ A, setA ] = useState(0);
const [ B, setB ] = useState(0);
return <div>
<button onClick={ () => {
setA( prevA => { // <-- setA might be called multiple times, with the same value for prevA
setB( prevB => prevB + 1 ); // <-- setB might be called multiple times, with a _different_ value for prevB
return prevA + 1;
} );
} }>set count</button>
{ A } / { B }
</div>;
}
例如这不会在副作用之后显示当前值,直到组件由于其他原因重新渲染,例如增加count:
export function DoSideEffect(){
const someValueRef = useRef(0);
const [ count, setCount ] = useState(0);
return <div>
<button onClick={ () => {
setCount( prevCount => {
someValueRef.current = someValueRef.current + 1; // <-- some side effect
return prevCount; // <-- value doesn't change, so react doesn't re-render
} );
} }>do side effect</button>
<button onClick={ () => {
setCount(prevCount => prevCount + 1 );
} }>set count</button>
<span>{ count } / {
someValueRef.current // <-- react doesn't necessarily display the current value
}</span>
</div>;
}
2。遵循反应原则
您不应该将副作用放在更新程序函数中,因为它验证了一些原则,例如关注点分离和编写声明性代码。
关注点分离:
setCount 应该只设置count。
编写声明性代码:
通常,您应该编写代码declarative, not imperative。
IE。您的代码应该“描述”状态应该是什么,而不是一个接一个地调用函数。
IE。你应该写 "B 的值应该是 X,依赖于 A" 而不是 "改变 A,然后改变 B"
在某些情况下,React 对您的副作用一无所知,因此您需要自己注意保持一致的状态。
有时你无法避免编写一些命令式代码。
useEffect 可以帮助您保持状态一致,例如将一些命令式代码与一些状态相关联,也就是。 “指定依赖关系”。
如果你不使用useEffect,你仍然可以编写工作代码,但你只是没有使用 react 为此目的提供的工具。你没有按照应有的方式使用 React,你的代码变得不那么可靠了。