Search code examples
reactjsreact-hooksfetchuse-effect

reactjs useEffect cleanup function after fetching data


I've read some good practices in reactjs using useEffect. I have a situation which I separated my function to fetch the data and call it on the useEffect hook. How could I make some cleanup functions in this situation. ?

I've seen some useEffect cleanup like these:

useEffect(() => {
  let isActive = true;

  fetch('https://jsonplaceholder.typicode.com/todos/1')
    .then((response) => response.json())
    .then((data) => {
      if (isActive) {
        setTodo(data);
      }
    })
    .catch((error) => console.log(error.message));

  return () => {
    isActive = false;
  };
}, []);

From the example above, the fetch function is inside with useEffect, now how can I perform some cleanup if something like this situation:

const getTodos = async () => {        
        try {
            const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
            const todos = await response.json();
            if(todos) {
                setTodos(todos);
            }
        }catch(e) {
            console.log(e);
        }
    }    

useEffect(() => {
        let mountedTodos = true;
        getTodos();

        return () => {
            mountedTodos = false;
        }
    },[])

Solution

  • This could be handled in multiple ways.

    • You could have mountedTodos as a global variable outside the component.

    • You could defined mountedTodos as an object and pass it to getTodos function.

    However, I suggest you to use an AbortController

    const getTodos = async (signal) => {        
        try {
            const response = await fetch(/*url*/, { signal });
                const todos = await response.json();
                if(!signal.aborted) {
                    setTodos(todos);
                }
            }catch(e) {
                console.log(e);
            }
        }    
    
    useEffect(() => {
       const abortController = new AbortController();
       getTodos(abortController.signal);
    
       return () => abortController.abort();
    },[])
    

    Note: You should add getTodos in the dependency array of the useEffect hook and to avoid infinite loop of state update and re-render, wrap getTodos in useCallback hook.