React 的 useEffect 中更高级的比较

Posted

技术标签:

【中文标题】React 的 useEffect 中更高级的比较【英文标题】:More advanced comparison in React's useEffect 【发布时间】:2020-01-23 15:37:27 【问题描述】:

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

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

useEffect(
  () => doSomething(), 
  [myInstance],
  (prev, curr) =>  /* compare prev[0].value with curr[0].value */ 
);

请问我从 React 文档中遗漏了什么,或者有什么方法可以在已经存在的基础上实现这样的钩子吗?

如果有办法实现它,它会这样工作:第二个参数是一个依赖数组,就像来自 React 的 useEffect 钩子,第三个是带有两个参数的回调:依赖数组上一次渲染,以及依赖数组当前渲染

【问题讨论】:

你可以使用 React.memo 函数 【参考方案1】:

你可以使用 React.memo 函数:

const areEqual = (prevProps, nextProps) => 
  return (prevProps.title === nextProps.title)
;

export default React.memo(Component, areEqual);

或为此使用自定义钩子:

How to compare oldValues and newValues on React Hooks useEffect?

【讨论】:

【参考方案2】:

class based components 中很容易执行deep comparisoncomponentDidUpdate 提供previous propsprevious state 中的snapshot

componentDidUpdate(prevProps, prevState, snapshot)
    if(prevProps.foo !== props.foo) /* ... */ 
 

问题是useEffect 它与componentDidUpdate 不完全一样。考虑以下

useEffect(() =>
    /* action() */
,[props])

action() 被调用时,您唯一可以断言当前props 是它已更改(浅比较断言为false)。您不能拥有prevProps 的快照,因为hooks 就像常规函数一样,没有确保同步性(和注入参数)的生命周期的一部分(并且没有实例)。实际上,唯一能确保 hooks 值完整性的是order of execution。

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 将初始值存储在 currentprops 更改触发内部重新渲染 Component useEffect 被调用 usePrevious 被调用

注意usePrevious 总是在useEffect 之后调用(记住,顺序很重要!)。因此,每次您在 useEffect 内时,current 的值 useRef 总是会落后一个渲染。

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)

【讨论】:

我无法弄清楚这是如何工作的。如果依赖项是一个属性,这似乎不起作用 这适用于 AB 的 props、state 或任何其他值 很抱歉打扰您了,您能详细解释一下吗?我在 React 文档站点上读到了这个自定义钩子,但不能说我 100% 理解它。是否与分发效果的方式有关?谢谢! 我会给出我的答案

以上是关于React 的 useEffect 中更高级的比较的主要内容,如果未能解决你的问题,请参考以下文章

React常用hook的优化useEffect浅比较

如何比较 React Hooks useEffect 上的 oldValues 和 newValues?多次重新渲染

[react] useEffect和useLayoutEffect有什么区别?

React useEffect() 无限重新渲染以获取所有尽管有依赖关系

react之Hook的useEffect详解

关于 React.useEffect() 和 React.useState() 的问题