我正在寻找一种方法来执行更高级的比较,而不是useEffect
React 钩子的第二个参数。
具体来说,我正在寻找更像这样的东西:
useEffect(
() => doSomething(),
[myInstance],
(prev, curr) => { /* compare prev[0].value with curr[0].value */ }
);
我从 React 文档中遗漏了什么吗,或者有什么方法可以在已经存在的东西之上实现这样的钩子,请问?
如果有一种方法可以实现这一点,这就是它的工作原理:第二个参数是一个依赖项数组,就像来自 React 的useEffect
钩子一样,第三个参数是带有两个参数的回调:上一个渲染时的依赖项数组,以及当前渲染时的依赖项数组。
您可以使用React.memo函数:
const areEqual = (prevProps, nextProps) => {
return (prevProps.title === nextProps.title)
};
export default React.memo(Component, areEqual);
或者为此使用自定义钩子:
如何在 React Hooks 上使用效果来比较 oldValues 和 newValues?
在class based components
很容易执行deep comparison
。componentDidUpdate
提供了previous props
和previous state
snapshot
componentDidUpdate(prevProps, prevState, snapshot){
if(prevProps.foo !== props.foo){ /* ... */ }
}
问题是useEffect
它不完全像componentDidUpdate
。请考虑以下事项
useEffect(() =>{
/* action() */
},[props])
当调用action()
时,您唯一可以断言当前props
是它已更改(浅层比较断言为false
(。您不能拥有prevProps
原因的快照hooks
就像常规函数一样,没有生命周期的一部分(也没有实例(来确保同步性(并注入参数(。实际上,确保钩子价值完整性的唯一因素是执行顺序。
usePrevious
的替代品
更新前检查值是否相等
const Component = props =>{
const [foo, setFoo] = useState('bar')
const updateFoo = val => foo === val ? null : setFoo(val)
}
这在某些情况下很有用,当您需要确保effect
只运行一次(在您的用例中没有用(。
useMemo
: 如果要执行比较以防止不必要的render
调用(shoudComponentUpdate
(,那么useMemo
就是要走的路
export React.useMemo(Component, (prev, next) => true)
但是,当您需要访问已在运行的效果中的previous
值时,没有其他选择。因为如果您已经在useEffect
,则意味着dependency
它已经更新(当前渲染(。
为什么usePrevious
有效useRef
不仅适用于refs
,这是一种非常简单的方法,可以在不触发重新渲染的情况下mutate
值。所以循环如下
Component
安装完毕usePrevious
将初始值存储在current
props
触发Component
内部重新渲染的更改useEffect
被称为usePrevious
被称为
请注意,usePrevious
总是在useEffect
之后调用(请记住,顺序很重要!因此,每次您在useEffect
useRef
的current
值将始终落后一个渲染。
const usePrevious = value =>{
const ref = useRef()
useEffect(() => ref.current = value,[value])
}
const Component = props =>{
const { A } = props
useEffect(() =>{
console.log('runs first')
},[A])
//updates after the effect to store the current value (which will be the previous on next render
const previous = usePrevious(props)
}
我最近遇到了同样的问题,对我有用的解决方案是创建自定义useStateWithCustomComparator
钩子。
在你的例子中,这意味着要替换
const [myInstance, setMyInstance] = useState(..)
跟
const [myInstance, setMyInstance] = useStateWithCustomComparator(..)
我在 Typescript 中的自定义钩子的代码如下所示:
const useStateWithCustomComparator = <T>(initialState: T, customEqualsComparator: (obj1: T, obj2: T) => boolean) => {
const [state, setState] = useState(initialState);
const changeStateIfNotEqual = (newState: any) => {
if (!customEqualsComparator(state, newState)) {
setState(newState);
}
};
return [state, changeStateIfNotEqual] as const;
};