Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react router unmount function component

I am using React Router and have two routes that render the same component:

<Switch>
    <Route path="/aaa" component={Cmp} />
    <Route path="/bbb" component={Cmp} />
</Switch>

This is Cmp implementation:

class Cmp extends Component {
    componentWillUnmount() {
        console.log('******************* UNMOUNTED');
    }

    render() {
        return null;
    }
}

As I expect, navigating between /aaa and /bbb doesn't unmount Cmp.

I am moving to hooks so I rewrote the component:

function Cmp() {
    useEffect(() => {
        return () => {
            console.log('******************* UNMOUNTED');
        };
    });

    return null;
}

And very surprisingly, when running the app, navigating between /aaa and /bbb console.log that Cmp was unmounted.
Any idea how to prevent the unnecessary unmount-mount using function component and hooks?

like image 890
Naor Avatar asked May 15 '19 13:05

Naor


People also ask

How do you unmount a functional component in React?

In the unmounting (or deletion, or "cleanup") phase, we have just one lifecycle method to help us out: componentWillUnmount . componentWillUnmount is the last function to be called immediately before the component is removed from the DOM.

How do you unmount a component React hook?

Use the useEffect hook to run a react hook when a component unmounts. The function we return from the useEffect hook gets invoked when the component unmounts and can be used for cleanup purposes.

How would you call an API when the functional component is mounted and unmounted?

The useEffect() hook is called when the component is mounted and sets the mounted. current value to true . The return function from the useEffect() hook is called when the component is unmounted and sets the mounted.

How can we perform componentDidMount and componentWillUnmount in a functional component?

Combining both componentDidMount and componentWillUnmount It is possible to combine both componentDidMount , and componentWillUnmount in the same useEffect function call. Meaning handling a component will unmount, and component will mount call in the same snippet.


2 Answers

If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run. This isn’t handled as a special case — it follows directly from how the dependencies array always works. ...read more

Now your effect is called on every rerender of Cmp component. You have to pass the second argument with an empty array to useEffect if you want to call your effect only on unmounting:

useEffect(() => {
    return () => {
        console.log('******************* UNMOUNTED');
    };
}, []);
like image 181
Andrii Golubenko Avatar answered Sep 18 '22 06:09

Andrii Golubenko


This is a very common issue people are facing with useEffect hook.

useEffect hook will be called everytime the component is re-rendered. The second argument of hook expects a dependency array, so the hook will only be called if the dependencies have changed. And if you provide empty array to it, hook will run only on mount and the returned function will be called before unmount.

TIP: Add this ESLint plugin to your project to find such hooks related issues. https://www.npmjs.com/package/eslint-plugin-react-hooks

import React, { useEffect } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch, Link } from 'react-router-dom';

import './styles.css';

const DemoComponent = () => {
  useEffect(() => {
    return () => {
      console.log('******************* UNMOUNTED');
    };
  }, []);
  return <div>Demo Component</div>;
};

const HomeComponent = () => {
  return <div>Home Component</div>;
};

function App() {
  return (
    <BrowserRouter>
      <div>
        <Link to="/">To Home</Link>
        <br />
        <Link to="/aaa">To AAA</Link>
        <br />
        <Link to="/bbb">To BBB</Link>
      </div>
      <Switch>
        <Route path="/(aaa|bbb)" component={DemoComponent} />
        <Route path="/" component={HomeComponent} />
      </Switch>
    </BrowserRouter>
  );
}

const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);  

Here is the working example: https://codesandbox.io/s/9l393o7mlr

like image 26
Murli Prajapati Avatar answered Sep 20 '22 06:09

Murli Prajapati