How properly unmount state within ComponentWillUnmount to avoid memory leaks?

47 Views Asked by At

I pass a component state as a prop to another component. It is really large. Do I have to reset the state while parent component unmounted? I just want to avoid memory leaks.

componentDidMount(){
  fetch({ /* ... */ })
    .then(res => res.json())
    .then((responseData) => {
      this.setState({
        result: responseData.meta.data
      })
    })
}
  
componentWillUnmount(){
  this.setState({
    result: undefined // IS THAT RIGHT APPROACH?
  })
}

render() {
  return (
    <DataComponent data={this.state.result}>

    </DataComponent>
  );
}
3

There are 3 best solutions below

2
Farshad Kazemi On BEST ANSWER

To prevent memory leaks, you don't have to perform this state change in componentWillUnmount method. Unmounting the component would remove the state, and so would the reference to the responseData.meta.data, which you stated is large.

There is also another downside to this solution. This type of optimization lowers your code readability and may complicate the maintenance process in future. So try not to use this in your code as it is considered against the clean code principle.

0
Magnie Mozios On

If your component uses custom element.addEventListener()s, then you will want to use removeEventListener() in your componentWillUnmount() function. Otherwise, all the clean up for state, onClick, and other React-specific functionality is done automatically.

A use case where I've needed to clean up event listeners is when I was using a custom vanilla-JS library that didn't have a React equivalent and I had to manually set up and later remove listeners. If I didn't and I recreated the JS component, then events would be handled twice (or more depending on how many times the component was recreated) causing weird things to happen.

0
Drew Reese On

Do I have to reset the state while parent component unmounted?

You don't need to cull the local component state, React/Javascript handles garbage collecting it when it is no longer referenced.

There's also no point an enqueueing a state update in componentWillUnmount since the component is unmounting and there will be no further render cycle.

Note also from the componentWillUnmount docs:

componentWillUnmount()

componentWillUnmount()

componentWillUnmount() is invoked immediately before a component is unmounted and destroyed. Perform any necessary cleanup in this method, such as invalidating timers, canceling network requests, or cleaning up any subscriptions that were created in componentDidMount().

You should not call setState() in componentWillUnmount() because the component will never be re-rendered. Once a component instance is unmounted, it will never be mounted again.

Use this lifecycle method to clean up non-state-related code, like event listeners, timers, subscriptions, cancel in-flight network requests, etc.

controller = null;

componentDidMount() {
  this.controller = new AbortController();
  const { signal } = this.controller;

  fetch({ /* ... */ }, { signal })
    .then(res => res.json())
    .then((responseData) => {
      this.setState({
        result: responseData.meta.data
      });
    });
}
  
componentWillUnmount() {
  this.controller?.abort();
}