loading...

React Hook - Clean Up useEffect

iquirino profile image Igor Quirino Originally published at wareboss.com ・3 min read

React (2 Part Series)

1) React Hook – Async function in useEffect 2) React Hook - Clean Up useEffect

From: https://wareboss.com/react-hook-clean-up-useeffect/

Last article we learn about Asynchronous actions on useEffect and our correct usage (React Hook - Async funcion in useEffect).

Today we will see how to use the clean up function of useEffect React Hook.

When you update a state from an unmounted component, React will throw this error:

"Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method."

useEffect(() => {
    //Do all the job, for example, subscribe a websocket channel
    return function(){
        //Unsubscribe websocket channel
    };
}, []);

Prevent update on unmounted component:

Here you'll learn how to prevent this problem

  useEffect(() => {
    let isCancelled = false;
    const runAsync = async () => {
      try {
        if (!isCancelled) {
          // do the job
        }
      } catch (e) {
        if (!isCancelled) {
          throw e;
        }
      }
    };

    runAsync();

    return () => {
      isCancelled = true;
    };
  }, [...]);

Usage with setInterval/setTimeout:

This is a nice solution to abort setInterval/setTimeout:

useEffect(() => {
  const interval = setInterval(() => {
    console.log('Five Seconds!');
  }, 5000);
  return () => clearInterval(interval);
}, []);

Imagine this use case: you opened this component and then closed.
Withou clean up you will continues running the setInterval callback.


Usage with Firestore Realtime Database:

This is useful when using Firestore Realtime Database:

useEffect(() => {
    //Subscribe: firebase channel
    const cleanUp = firebase.firestore().collection('photos') .doc(id)
        .onSnapshot( doc => {
            setLoading(false);
            setPhotos(doc)
        }, err => { setError(err); }
    );
    return () => cleanUp(); //Unsubscribe
 }, []);

If you forgot to clean your firestore subscription, you may receive unnecessary requests.


Usage with fetch + AbortController:

Cancel fecth with AbortController from fetch/es6:

  useEffect(() => {
    const abortController = new AbortController();
    const fetchData = async () => {
      try {
        const ret = await fetch("/companies", { signal: abortController.signal });
        const data = await ret.json();
        // ...
      }
      catch(error) {
        if (abortController.signal.aborted) {
          // cancelled
        }
        else
          throw error;
      };
    };

    fetchData();

    return () => abortController.abort();
  }, [companies]);

Usage with axios request:

Here is how to cancel the request with axios.

useEffect(() => {
  const source = axios.CancelToken.source();

  const fetchData = async () => {
    try {
      const response = await Axios.get("/companies", {
        cancelToken: source.token
      });
      // ...
    } catch (error) {
      if (Axios.isCancel(error)) {
        //cancelled
      } else {
        throw error;
      }
    }
  };

  fetchData()

  return () => {
    source.cancel();
  };
}, [companies]);

The useEffect function is the equivalent of componentDidMount in a React Class component.

The clean up function is the equivalent of componentWillUnmount in a React Class component.

Next article: React Class Component and React Function Component differences.

Bye bye!

React (2 Part Series)

1) React Hook – Async function in useEffect 2) React Hook - Clean Up useEffect

Posted on by:

iquirino profile

Igor Quirino

@iquirino

I love to help people to solve their problems.

Discussion

markdown guide
 

super helpful post! thanks so much!