Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: memory leaks in application #242

Merged
merged 4 commits into from
Nov 24, 2020

Conversation

kwajiehao
Copy link
Contributor

Overview

This PR fixes instances in the app where we attempt to perform state updates on unmounted components. It resolves issue #228.

Occasionally, when we navigate away from a layout on the CMS, or close a modal before it's done loading something, we receive the following error message in the console:

Warning: 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

The problem arises when we are awaiting some async operation, and setting state after the async operation completes. For example, I might be in the EditPage layout, and after I retrieve the page's content, I set that content into the component state.

The problem is that if I navigate away from the EditPage layout while it is retrieving the content (the async operation), the EditPage component unmounts, but the componentWillMount function, or the useEffect function will continue to run and attempt to set state after the async operation completes. This is why we get the error message about updating state on an unmounted component.

Solution

The solution is to only set state when we can be sure that the component is mounted. We can do this by introducing an _isMounted local variable, which is set to true when the async operation is run, but also define a cleanup function (either within the useEffect or as componentWillUnmount) which sets the _isMounted variable to false. Since state updates are only performed when _isMounted is true, we no longer attempt to update state after a component is unmounted. The caveat is that _isMounted needs to be defined as a normal variable, and not as state, since it needs to be updated synchronously for this to work.

Jie Hao Kwa added 4 commits November 19, 2020 07:20
Previously, if you tried to navigate away from a layout / component
while it was still performing an async operation, we would receive
the following error in the console:

```
Warning: 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
```

This is slightly differently-phrased if the component is a class component
but the idea is the same.

The solution to this is to specify a cleanup function. To execute this,
we define an `_isMounted` variable, and only set state updates when
this variable is set to true. In our cleanup function, we set this variable
back to false so that state updates are not performed on unmounted
components.

Reference: https://stackoverflow.com/questions/53949393/cant-perform-a-react-state-update-on-an-unmounted-component
This commit refactors the LoadingButton so that it runs the
callback in the proper order. Previously, we would attempt to
set the button to a loading state, await on the callback function,
and then set the button back to its non-loading state. The problem
is that the setState functions are not asynchronous so they do not
run on the same event loop as the callback. This commit refactors
the code so that the code is run more reactively using a useEffect.
Previously, React throws an error complaining about a memory leak
whenever we select an image in the EditPage layout. It turns out
this is because we attempt to set the LoadingButton component's
loading state to false even after the component has unmounted. This
is fixed by applying the same fix from a couple commits ago to the
LoadingButton component.
@kwajiehao kwajiehao requested a review from gweiying November 18, 2020 23:54
@kwajiehao kwajiehao linked an issue Nov 18, 2020 that may be closed by this pull request
Copy link
Contributor

@alexanderleegs alexanderleegs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@kwajiehao kwajiehao merged commit 498278c into staging Nov 24, 2020
@kwajiehao kwajiehao deleted the fix/unmount-components-when-navigated-away branch November 24, 2020 07:51
@kwajiehao kwajiehao mentioned this pull request Nov 25, 2020
26 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Memory leak bug because of unmounted Loading button
2 participants