实现 useUpdateEffect hook: 改造 useEffect 实现首次渲染时不执行副作用的钩子

123 阅读1分钟

实现 useUpdateEffect hook: 改造 useEffect 实现首次渲染时不执行副作用的钩子

最近在过 React 相关面试题的时候,遇到了一个有趣的题目,就是实现 useUpdateEffect hook,刚好前一段时间的工作中遇到了类似的场景,需要 useEffect 在首次渲染的时候不执行副作用,而在后续依赖更新的时候正常执行副作用。和这个面试题一样,当时也是用了useRef来实现。

让我们先来了解一下useRef:

const refContainer = useRef(initialValue);

useRef会返回一个可修改的 ref 对象,它的.current属性会被初始化为传入的参数(initialValue)。这个返回的对象会在这个组件的整个生命周期中保持,意味着只要你不去修改它,他会保持不变(就算在重新渲染之后)。

平时我们最常见使用useRef的场景是通过引用的方式访问一个子元素或者子组件。这里就不详细介绍这个用法啦。

除此之外,它还可以很方便的保持任何可修改的值,也就是前面我们说到的。

而之所以能够实现这个效果,是因为useRef()创建了一个纯 js 对象{current: ...},并且在每次渲染的时候都返回给你同一个 ref 对象。

因此,我们可以通过 useRef 来判断是否是首次渲染:

import { useRef } from "react";

export function useFirstMountState(): boolean {
  const isFirst = useRef(true);

  if (isFirst.current) {
    isFirst.current = false;

    return true;
  }

  return isFirst.current;
}

然后借助useFirstMountState来判断是否是首次渲染,并据此判断是否执行副作用:

import { useEffect } from "react";
import { useFirstMountState } from "./useFirstMountState";

const useUpdateEffect: typeof useEffect = (effect, deps) => {
  const isFirstMount = useFirstMountState();

  useEffect(() => {
    if (!isFirstMount) {
      return effect();
    }
  }, deps);
};

export default useUpdateEffect;