Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

useEffect lazy created cleanup function

I'm trying to create hook that is is using an effect in which side effect function returns the cleanup callback. However I want to call it only when component is unmounted, not on the rerender.

Normal approach when you call useEffect with empty deps array won't work here as the cleanup function is created only once, on the first call of the hook. But my clean up is created later, so there is no way to change it.


function useListener(data) {
  const [response, updateResponse] = useState(null);

  useEffect(
    () => {
      if (data) {
        const removeListener = callRequest(data, resp => {
          updateResponse(resp);
        });

        return removeListener;
      }
    },
    [data]
  );

  return response;
}

This comes down to a following problem: In normal class component, the willComponentUnmount could make a decision based on a current component state but in case of useEffect, state is passed via closure to the cleanup and there is no way to pass the information later if the state has changed

like image 286
Tomasz Kal Avatar asked Mar 28 '26 03:03

Tomasz Kal


1 Answers

You can use useRef to save and update your callback function

The useRef() Hook isn’t just for DOM refs. The “ref” object is a generic container whose current property is mutable and can hold any value, similar to an instance property on a class. more

function useListener(data) {
  const [response, updateResponse] = useState(null);
  const cleanUpCallbackRef = useRef(() => {});

  useEffect(
    () => {
      if (data) {
        cleanUpCallbackRef.current = callRequest(data, resp => {
          updateResponse(resp);
        });
      }
    },
    [data]
  );

  useEffect(() => {
    return () => {
      cleanUpCallbackRef.current();
    }
  }, []);
  return response;
}

I create a simple example here

like image 160
Andrii Golubenko Avatar answered Mar 29 '26 20:03

Andrii Golubenko