background

This is the third installment in a series on hooks by handwriting. Difficulty: ⭐️

Due to the useEffect mechanism in React, useEffect is performed during initial rendering regardless of the scene. So how do you implement componentDidUpdate in a class component?

Today takes you to implement a functional component version of componentDidUpdate.

demand

Now require the implementation of a custom hook: useUpdateEffect, after the implementation of the specific use and useEffect, the effect and componentDidUpdate the same.

const Test = () = > {
  const [num, setNum] = useState(0);

  useUpdateEffect(() = > {
    console.log(num, "Num after update");
  }, [num]);

  return (
    <div>
      {num}
      <button onClick={()= > setNum(num + 1)}>add</button>
    </div>
  );
};
Copy the code

coded

Step 1: Define the input/output structure.

export const useUpdateEffect: typeof useEffect = (effect, deps) = > {
  useEffect(() = > {
    return effect();
  }, deps);
};
Copy the code

Step 2: process the first rendering. The core here is to determine the timing of the first rendering. If it is the first rendering, do not execute the effect function passed in.

You can use useRef to determine if it’s the first rendering.

export const useUpdateEffect: typeof useEffect = (effect, deps) = > {
  const ref = useRef(true);

  useEffect(() = > {
    if (ref.current) {
      ref.current = false; // Set it to false for first rendering
    } else {
      return effect(); // Do it again when rendering
    }
  }, deps);
};
Copy the code

Step 3: Code optimization. In fact, we can separate the logic of whether it is the first time to render into a public hook: useFirstMountState, so that the code logic is clearer.

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

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

    return true;
  }

  return isFirst.current;
}
Copy the code

UseUpdateEffect after optimization:

export const useUpdateEffect: typeof useEffect = (effect, deps) = > {
  const isFirstMount = useFirstMountState(); // Is it the first render

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

conclusion

All the code covered in this article is in a github Demo. Give it a thumbs up ❤️❤️❤️.

You are welcome to leave a comment in the comments section to give better practice!