logoahooks dive
Effect

useUpdateEffect

用于更新 Effect Hook

用法

用法等同于 useEffect,但不同的是,会忽略首次执行,只在依赖更新时执行。

effectCount: 0

updateEffectCount: 0

源码

import { useEffect } from 'react';
import { createUpdateEffect } from '../createUpdateEffect';

export default createUpdateEffect(useEffect);
import { useRef } from 'react';
import type { useEffect, useLayoutEffect } from 'react';

type EffectHookType = typeof useEffect | typeof useLayoutEffect;

export const createUpdateEffect: (hook: EffectHookType) => EffectHookType =
  (hook) => (effect, deps) => {
    const isMounted = useRef(false);

    // for react-refresh
    hook(() => {
      return () => {
        isMounted.current = false;
      };
    }, []);

    hook(() => {
      if (!isMounted.current) {
        isMounted.current = true;
      } else {
        return effect();
      }
    }, deps);
  };

export default createUpdateEffect;

解读

首先,调用 createUpdateEffect 函数,传入 useEffect 函数。createUpdateEffect 函数接收一个函数作为参数,返回一个新函数。这样封装的目的是为了支持 useLayoutEffect 的用法。ahooks 中有很多类似的这种封装,因为需要同时支持 useEffectuseLayoutEffect 的用法。

直接把源码中的参数 hook 替换成 useEffect,再来看看实际的代码:

export const useUpdateEffect = (effect, deps) => {
  // 1. 使用 useRef 定义一个 ref 对象,用于记录组件是否已经挂载
  const isMounted = useRef(false)

  // 2. 使用 useEffect 监听组件的卸载,在组件卸载时,将 isMounted 的值设置为 false
  useEffect(() => {
    return () => {
      isMounted.current = false
    }
  }, [])

  // 3. 使用 useEffect 监听依赖的更新
  //    因为 useEffect 会在组件挂载时执行一次,但是由于 isMounted 的初始值为 false,所以会跳过这次 effect 的执行
  //    后续依赖更新时,才会执行 effect
  useEffect(() => {
    if (!isMounted.current) {
      isMounted.current = true
    } else {
      return effect()
    }
  }, deps)
}

Last updated on

On this page