0

I am using useEffect hook to fetch data from the server and these data are passed to a list, when I Signup I am getting a warning like below

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 a useEffect cleanup function.

const getUserData = () => {
  axios.get(`${API_URL}`).then((res) => {
    if (res.data) {
      setUserData(res.data);
    }
  });
};

useEffect(() => {
  getUserData();
}, []);

const logout = () => {
  signout(() => {
    history.push('/signin');
  });
};

return (
  <div>
    <button onClick={() => logout()}>Sign out </button>
  </div>
);
skyboyer
  • 22,209
  • 7
  • 57
  • 64
Gabriel Geelario
  • 227
  • 1
  • 2
  • 16
  • You got a syntax error in `history.push('/signin);`. You need to close the quote – Dominik May 25 '21 at 22:07
  • I have updated it – Gabriel Geelario May 25 '21 at 22:10
  • just like the error message says, you need to clean up any asynchronous tasks launched by your `useEffect` hook by returning a cleanup function. use it to either abort the request or ensure the component is still mounted before you call `setState`. – Dan O May 25 '21 at 22:13
  • Looks like your API request returns **after** you navigated away from this component via `history.push('/signin')`. Return a function in your `useEffect` to deal with that. – Dominik May 25 '21 at 22:14
  • Does this answer your question? [Can't perform a React state update on an unmounted component](https://stackoverflow.com/questions/53949393/cant-perform-a-react-state-update-on-an-unmounted-component) – Andy Ray May 25 '21 at 22:14
  • There are thousands of duplicates of this question on Stackoverflow. In the future when you create a question, Stackoverflow first shows you which questions might have already solved your problem. Be sure to review those as part of creating your question. – Andy Ray May 25 '21 at 22:15

1 Answers1

2

This happens when your component gets destroyed some of the code left to be executed is done after that destroying. In your case that is callback for API call setUserData(res.data);

Since you are using Axios for your http calls I would suggest to use cancel token to cancel API call on component destroy.

Generate cancel token from axios, pass it to the method getUserData and provide it to axios call. For that useEffect return method that will be executed when component destroys (and there cancel that code, thus cancelling that callback with state set):

const getUserData = (cancelToken) => {
  axios.get(`${API_URL}`, {cancelToken: cancelToken.token}).then((res) => {
    if (res.data) {
      setUserData(res.data);
    }
  });
};

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

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

const logout = () => {
  signout(() => {
    history.push('/signin');
  });
};

return (
  <div>
    <button onClick={() => logout()}>Sign out </button>
  </div>
);
Mario Petrovic
  • 7,500
  • 14
  • 42
  • 62