Search code examples
reactjsasynchronousreact-hooksusecallback

Why does useIsMounted return a callback instead of the value itself?


I'm referring to useIsMounted from usehooks-ts. I'm trying to understand why the function is returning useCallback(() => isMounted.current, []) instead of just isMounted.current.

I've tested both ideas in a CodeSandbox that just uses a setTimeout to simulate async work and I haven't found any issues returning the value instead of a callback. What am I missing?


Solution

  • For whatever reason the authors of this useIsMounted hook decided to return a function instead of the boolean isMounted value. The returned function is memoized so it can be safely passed as a callback to children components.

    Returning isMounted.current doesn't work though, but returning the entire isMounted ref does.

    Example:

    const useIsMounted = () => {
      const isMounted = useRef(false);
    
      useEffect(() => {
        isMounted.current = true;
    
        return () => {
          isMounted.current = false;
        };
      }, []);
    
      return isMounted;
    }
    

    And this requires consumers to know it's a React ref and that they need to unpack the current ref value.

    function Child() {
      const [data, setData] = useState("loading");
      const isMounted = useIsMounted();
    
      // simulate an api call and update state
      useEffect(() => {
        void delay(3000).then(() => {
          if (isMounted.current) setData("OK"); // <-- access ref value
        });
      }, [isMounted]);
    
      return <p>{data}</p>;
    }
    

    Edit why-does-useismounted-return-a-callback-instead-of-the-value-itself

    Seems it was just a design decision to return a memoized function.