假设我有3个输入:rate、sendAmount和receiveAmount。我把这3个输入放到useEffect上。规则如下:
如果sendAmount改变了,我计算receiveAmount = sendAmount * rate
如果receiveAmount改变了,我计算sendAmount = receiveAmount / rate
如果速率发生变化,当sendAmount > 0时,我计算receiveAmount = sendAmount * rate;当receiveAmount > 0时,我计算sendAmount = receiveAmount / rate
下面是代码和框https://codesandbox.io/s/pkl6vn7x6j来演示这个问题。
是否有一种方法来比较oldValues和newValues,如componentDidUpdate,而不是为这种情况下做3处理程序?
谢谢
下面是我使用usePrevious的最终解决方案
https://codesandbox.io/s/30n01w2r06
在本例中,我不能使用多个useEffect,因为每次更改都会导致相同的网络调用。这就是为什么我还使用changeCount来跟踪更改。这个changeCount还有助于仅从本地跟踪更改,因此可以防止由于服务器更改而引起的不必要的网络调用。
下面是Aadit M Shah的答案的Typescript版本。
我把它从useTransition重命名为usePrevious,因为useTransition已经存在于React中。
import { useEffect, useRef, useState } from 'react';
const usePrevious = <T extends any[],>(callback: (prev: T) => void, deps: T): void => {
const callbackRef = useRef<null | ((prev: T) => void)>(null);
useEffect(() => {
callbackRef.current = callback;
}, [callback]);
const depsRef = useRef<null | T>(null);
const [initial, setInitial] = useState(true);
useEffect(() => {
if (!initial && depsRef.current !== null && callbackRef.current !== null) {
callbackRef.current(depsRef.current);
}
depsRef.current = deps;
setInitial(false);
}, deps);
}
export default usePrevious;
用法:
usePrevious<[boolean]>(([prevIsOpen]) => {
console.log('prev', prevIsOpen);
console.log('now', isOpen);
}, [isOpen])
选项1 -当值改变时运行useEffect
const Component = (props) => {
useEffect(() => {
console.log("val1 has changed");
}, [val1]);
return <div>...</div>;
};
Demo
选项2 - useHasChanged钩子
比较当前值和以前值是一种常见的模式,它证明了它自己的自定义钩子隐藏了实现细节。
const Component = (props) => {
const hasVal1Changed = useHasChanged(val1)
useEffect(() => {
if (hasVal1Changed ) {
console.log("val1 has changed");
}
});
return <div>...</div>;
};
const useHasChanged= (val: any) => {
const prevVal = usePrevious(val)
return prevVal !== val
}
const usePrevious = (value) => {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
Demo
我不喜欢上面的任何答案,我想要传递一个布尔值数组的能力,如果其中一个是真的,那么重新渲染
/**
* effect fires if one of the conditions in the dependency array is true
*/
export const useEffectCompare = (callback: () => void, conditions: boolean[], effect = useEffect) => {
const shouldUpdate = useRef(false);
if (conditions.some((cond) => cond)) shouldUpdate.current = !shouldUpdate.current;
effect(callback, [shouldUpdate.current]);
};
//usage - will fire because one of the dependencies is true.
useEffectCompare(() => {
console.log('test!');
}, [false, true]);