DEV Community

loading...

Component Will Unmount How to use componentWillUnmount with Functional Components in React

Robert Marshall
A React/Gatsby JS developer based in Leeds, UK
Originally published at thoughtsandstuff.com on ・2 min read

Most up to date version of this article: https://thoughtsandstuff.com/componentwillunmount-functional-components-react


Functional components are far more efficient than class based components. There is also less code that is needed to be written to achieve the same goal.

However, I could not get my head around how functional components could implement the use of life-cycle events without needing to be changed to a class.

Turns out everything can be managed through useEffect.

I have used useEffect in the past to manage API calls, and what happened on a componentWillMount, but never componentWillUnmount. It turns out both are very similar!

How to manage componentWillMount with useEffect

To understand how we can use componentWillUnmount, first we need to look at how the component manages mounting with useEffect.

import React, { useEffect } from 'react';
const ComponentExample => () => {
   useEffect( () => {
      // Anything in here is fired on component mount.
   }, []);
}
Enter fullscreen mode Exit fullscreen mode

If we pass an empty array as the second argument, it tells useEffect to fire on component load. This is the only time it will fire.

With this in mind, how can we alter the code to work with componentWillUnmount? Turns out the solution is very simple.

How to manage componentWillUnmount with useEffect

If you add a return function inside the useEffect function, it is triggered when a component unmounts from the DOM. This looks like:

import React, { useEffect } from 'react';
const ComponentExample => () => {
    useEffect(() => {
        return () => {
            // Anything in here is fired on component unmount.
        }
    }, [])
}
Enter fullscreen mode Exit fullscreen mode

Combining both solutions

This means that you can use componentDidMount, and componentWillUnmount in the same useEffect function call. Dramatically reducing the amount of code needed to manage both life-cycle events. Like so:

import React, { useEffect } from 'react';
const ComponentExample => () => {
    useEffect(() => {
        // Anything in here is fired on component mount.
        return () => {
            // Anything in here is fired on component unmount.
        }
    }, [])
}
Enter fullscreen mode Exit fullscreen mode

Discussion (13)

Collapse
arnabmunshi profile image
ARNAB MUNSHI

Hi, I need a help

  componentDidMount() {  
    this._subscribe();
  }

  componentWillUnmount() {
    this._unsubscribe();
  }

  async _subscribe() {
    const batteryLevel = await Battery.getBatteryLevelAsync();
    this.setState({ batteryLevel });
    this._subscription = Battery.addBatteryLevelListener(({ batteryLevel }) => {
      this.setState({ batteryLevel });
      console.log('batteryLevel changed!', batteryLevel);
    });
  }

  _unsubscribe() {
    this._subscription && this._subscription.remove();
    this._subscription = null;
  }

How to convert this in functional component ?
I have done something like this ...

  const getLevel = async () => {
    console.log("A: " + (await Battery.getBatteryLevelAsync()));

    let batteryLevel = Math.round((await Battery.getBatteryLevelAsync()) * 100);
    setLevel(batteryLevel);
    Battery.addBatteryLevelListener(({ batteryLevel }) => {
      batteryLevel = Math.round(batteryLevel * 100);
      setLevel(batteryLevel);

      console.log("B: " + batteryLevel);
    });
  };

  useEffect(() => {
    // Anything in here is fired on component mount.
    // componentDidMount
    getLevel();

    // componentWillUnmount
    return () => {
      // Anything in here is fired on component unmount.
    };
  }, []);

I am facing problem in

return function

Collapse
robmarshall profile image
Robert Marshall Author

If you don't need anything to fire on component unmount, you can remove the return.

  useEffect(() => {
    getLevel();
  }, []);
Collapse
gopeeey profile image
gopeeey

Thank you very much for this

Collapse
vladanpro profile image
Vladan Profirovic

import React, { useEffect } from 'react';
const ComponentExample => () => {
useEffect( () => {
// Anything in here is fired on component mount.
}, []);
}
hi srry this show me that is fired on component mount but not on will mount, so i try to find what is best solution to replace componentWillMount. Tnx.

Collapse
amahecool profile image
amahecool • Edited

the returned function fires on component Re-render also. How to you check if its an unmount or just a re-render ?
Basically its just a clean up function which runs every time the useEffect is used (except the first time)

Collapse
robmarshall profile image
Robert Marshall Author

I suppose you could use a useRef to track the render (it will not be cleaned on a rerender). Depends on what you need it to do.

Collapse
pablobion profile image
Pablo Bion

Very cool!

Collapse
rahulbhadhoriya profile image
Rahul Bhadhoriya

Thanks very much

Collapse
seojeek profile image
Alex Vallejo

"Parsing error: Unexpected token, expected ","" is what i get when i try to return that

Collapse
robmarshall profile image
Robert Marshall Author

Looks like you have a typo?

Collapse
umeredava profile image
Umar Sanil

Thanks

Collapse
ankitalphaq profile image
Ankit Kumar Gupta

Hey, do we have some restrictions with using the current state values inside ComponentWillUnmount cleanup function ?
Few of my state values are reseted before my code could run 😔

Collapse
robmarshall profile image
Robert Marshall Author

Able to give a bit more context? If you are passing this state out of the component (e.g. to a parent) and then unmounting this component I imagine you would have problems.