skip to Main Content

I have implemented two hooks. They are useWatch1 and useWatch2, respectively.

The function of useWatch is to execute a cb function when the listening value changes.

The user first clicks the ADD COUNT button a few times, and then the count value will increase. Then the user clicks the ADD ID button, and the count value will be set to 0. useWatch2 meets expectations, but useWatch1 cannot. I would like to know why?

import { useRef, useState } from "react";

function useWatch1(current, cb) {
  const isFirstRender = useRef(true);
  const prevRef = useRef(null);

  if (isFirstRender.current) {
    prevRef.current = current;
    isFirstRender.current = false;
  } else if(prevRef.current !== current){
    prevRef.current = current;
    cb();
  }
}

function useWatch2(current, cb) {
  const [prev, setPrev] = useState(current);

  if (current !== prev) {
    setPrev(current);
    cb();
  }
}

function MyCpm({ id }) {
  const [count, setCount] = useState(0);

  // useWatch1(id, () => {
  //   setCount(0);
  // });

  useWatch2(id, () => {
    setCount(0);
  });

  console.log("render", count);

  return (
    <>
      <button
        onClick={() => {
          setCount((c) => c + 1);
        }}
      >
        ADD COUNT
      </button>
      <span>count: {count}</span>
      <span>-----</span>
      <span>id: {id}</span>
    </>
  );
}

function App() {
  const [id, setId] = useState(0);

  return (
    <>
      <button
        onClick={() => {
          setId((id) => id + 1);
        }}
      >
        ADD ID
      </button>
      <MyCpm id={id}></MyCpm>
    </>
  );
}

export default App;

2

Answers


  1. You’ve overcomplicated the situation – there’s documented ability to "reset" state (unmount/mount) components using keys

    <MyCpm id={id} key={id}></MyCpm>
    
    Login or Signup to reply.
  2. useWatch1 would work if you do not use React Strict Mode. With Strict Mode enabled, React will (re)render the component twice to allow the programmer to find accidental impurities in the component. The first rerender will set prevRef.current to the new value, so the values will no longer differ on the second rerender, which is the one that is used to update the DOM. useWatch2 has no such issue as React will simply ignore state updates on the first (discarded) rerender.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search