реагировать на компонент функции размонтирования маршрутизатора - PullRequest
1 голос
/ 15 мая 2019

Я использую React Router и у меня есть два маршрута, которые отображают один и тот же компонент:

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

Это реализация Cmp:

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

    render() {
        return null;
    }
}

Как я и ожидал, навигация между /aaa и /bbb не размонтирует Cmp.

Я перехожу на крючки, поэтому переписал компонент:

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

    return null;
}

И что очень удивительно, при запуске приложения, переходя между /aaa и /bbb console.log, что Cmp был размонтирован.
Любая идея, как предотвратить ненужное размонтирование с помощью компонента функции и хуков?

Ответы [ 2 ]

2 голосов
/ 15 мая 2019

Это очень распространенная проблема, с которой люди сталкиваются с useEffect hook.

useEffect hook будет вызываться каждый раз, когда компонент перерисовывается.Второй аргумент hook ожидает массив зависимостей, поэтому ловушка будет вызываться только в случае изменения зависимостей.И если вы предоставите ему пустой массив, ловушка будет работать только при монтировании, и возвращаемая функция будет вызываться перед размонтированием.

СОВЕТ: Добавьте этот плагин ESLint в ваш проект, чтобы найти такие проблемы, связанные с ловушками.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);  

Вот рабочий пример: https://codesandbox.io/s/9l393o7mlr

1 голос
/ 15 мая 2019

Если вы хотите запустить эффект и очистить его только один раз (при монтировании и демонтировании), вы можете передать пустой массив ([]) в качестве второго аргумента.Это говорит React, что ваш эффект не зависит от каких-либо значений из реквизита или состояния, поэтому его не нужно повторно запускать.Это не обрабатывается как особый случай - это следует непосредственно из того, как всегда работает массив зависимостей. ... читать дальше

Теперь ваш эффект вызывается при каждом повторном рендере компонента Cmp.Вам нужно передать второй аргумент с пустым массивом в useEffect, если вы хотите вызывать свой эффект только при размонтировании:

useEffect(() => {
    return () => {
        console.log('******************* UNMOUNTED');
    };
}, []);
...