In this series, I will read the source code of ahooks, which is used to familiarized myself with the writing method of custom hooks, and improve my ability to write custom hooks.

In order to distinguish it from the original comments of the code, the personal understanding section uses the beginning of ///, which is not related to the triple slash instruction, just to distinguish it.

Review past

  • Ahooks source code interpretation series
  • Ahooks Source Code Interpretation Series – 2
  • Ahooks Source Code Interpretation series – 3
  • Ahooks Source Code Interpretation series – 4
  • Ahooks Source Code Interpretation series – 5
  • Ahooks Source Code Interpretation series – 6
  • Ahooks Source Code Interpretation series – 7

The series of articles is already the eighth, it seems that my strength is too strong, the previous 7 have not been pointed out mistakes, then I will continue to keep it. Hooks for LifeCycle section today.

LifeCycle

useMount

Simulate componentDidMount(), run only on first render.

import { useEffect } from 'react';

const useMount = (fn: () => void) = > {
  UseEffect is used to implement lifecycle related hooks
  useEffect(() = > {
    fn(); /// Note that there is no return, so no cleanup is performed} []); };export default useMount;

Copy the code

useUnmount

Simulates componentWillUnmount(), which runs only when the component is unmounted.

import { useEffect } from 'react';
import usePersistFn from '.. /usePersistFn';
import { isFunction } from '.. /utils';

const useUnmount = (fn: any) = > {
  const fnPersist = usePersistFn(fn);

  useEffect(
    () = > () = > {
      if(isFunction(fnPersist)) { fnPersist(); }}, []); };export default useUnmount;
Copy the code

useUnmountedRef

“Have you gone?

Returns the flag bit that indicates whether the component is uninstalled.

import { useRef, useEffect } from 'react';

const useUnmountedRef = () = > {
  const unmountedRef = useRef(false);
  useEffect(() = > {
    return () = > {
      /// The dependency array is empty, so it is only true when the component is unloaded
      unmountedRef.current = true; }; } []);return unmountedRef;
};

export default useUnmountedRef;

Copy the code

useTrackedEffect

“You see that this is the case.”

Useeffects that provide specific change dependencies

import { useEffect, useRef, DependencyList } from 'react';

const useTrackedEffect = (effect, deps? : DependencyList) = > {
  const previousDepsRef = useRef<DependencyList>();
  /// compare dependency changes to use! == To determine if there is a change, return the index of the change item in the dependency list
  const diffTwoDeps = (deps1, deps2) = > {
    //Let's do a reference equality check on 2 dependency list.
    //If deps1 is defined, we iterate over deps1 and do comparison on each element with equivalent element from deps2
    //As this func is used only in this hook, we assume 2 deps always have same length.
    return deps1
      ? deps1.map((_ele, idx) = >(deps1[idx] ! == deps2[idx] ? idx : -1)).filter((ele) = > ele >= 0)
      : deps2
      ? deps2.map((_ele, idx) = > idx)
      : [];
  };
  useEffect(() = > {
    let changes = diffTwoDeps(previousDepsRef.current, deps);
    const previousDeps = previousDepsRef.current;
    previousDepsRef.current = deps;
    return effect(changes, previousDeps, deps); /// provide variable value index, previous dependency array, current dependency array to cb
  }, deps);
};

export default useTrackedEffect;

Copy the code

useDebounceEffect

UseEffect with anti – shake function

import { useEffect, EffectCallback, DependencyList, useState } from 'react';
import { DebounceOptions } from '.. /useDebounce/debounceOptions';
import useDebounceFn from '.. /useDebounceFn';
import useUpdateEffect from '.. /useUpdateEffect';
import useUnmount from '.. /useUnmount';

function useDebounceEffect(effect: EffectCallback, deps? : DependencyList, options? : DebounceOptions,) {
  const [flag, setFlag] = useState({});

  const { run, cancel } = useDebounceFn(() = > {
    setFlag({}); /// Update flag to trigger useUpdateEffect to trigger effect callback
  }, options);
  
  /// Trigger an effect on the first render
  useEffect(() = > {
    return run();
  }, deps);
  / / / clean up
  useUnmount(cancel);

  useUpdateEffect(effect, [flag]);
}

export default useDebounceEffect;

Copy the code

useThrottleEffect

UseEffect with throttling function

import { useEffect, EffectCallback, DependencyList, useState } from 'react';
import { ThrottleOptions } from '.. /useThrottle/throttleOptions';
import useThrottleFn from '.. /useThrottleFn';
import useUpdateEffect from '.. /useUpdateEffect';
import useUnmount from '.. /useUnmount';

function useThrottleEffect(effect: EffectCallback, deps? : DependencyList, options? : ThrottleOptions,) {
  const [flag, setFlag] = useState({});

  const { run, cancel } = useThrottleFn(() = > {
    setFlag({});
  }, options);

  useEffect(() = > {
    return run();
  }, deps);

  useUnmount(cancel);

  useUpdateEffect(effect, [flag]);
}

export default useThrottleEffect;

Copy the code

useUpdate

Simulation forceUpdate ()

import { useCallback, useState } from 'react';

const useUpdate = () = > {
  const [, setState] = useState({});

  return useCallback(() = > setState({}), []); /// trigger a component update by updating state when called
};

export default useUpdate;

Copy the code

useUpdateEffect

Simulate componentDidUpdate, ignoring useEffect for the first rendering version. This has nothing to do with useUpdate.

import { useEffect, useRef } from 'react';

const useUpdateEffect: typeof useEffect = (effect, deps) = > {
  const isMounted = useRef(false);

  useEffect(() = > {
    if(! isMounted.current) { isMounted.current =true;
    } else {
      return effect(); /// Ignores the first render and only runs when it depends on updates
    }
  }, deps);
};

export default useUpdateEffect;

Copy the code

useUpdateLayoutEffect

Equivalent componentDidUpdate, ignores the first rendering version of useLayoutEffect.

Learn more about React useLayoutEffect and useEffect execution timing

/* eslint consistent-return: 0 */

import { useLayoutEffect, useRef } from 'react';

const useUpdateLayoutEffect: typeof useLayoutEffect = (effect, deps) = > {
  const isMounted = useRef(false);

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

export default useUpdateLayoutEffect;

Copy the code

The above content due to my level problem is inevitable error, welcome to discuss feedback.