在 React 的使用效果中更高级的比较



我正在寻找一种方法来执行更高级的比较,而不是useEffectReact 钩子的第二个参数。

具体来说,我正在寻找更像这样的东西:

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 comparisoncomponentDidUpdate提供了previous propsprevious statesnapshot

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之后调用(请记住,顺序很重要!因此,每次您在useEffectuseRefcurrent值将始终落后一个渲染。

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;
};

相关内容

  • 没有找到相关文章

最新更新