Reactjs, почему useEffect иногда запускается при каждом монтировании / рендеринге, а не только сначала

У меня есть useEffect в моих маршрутах в App.js

    <Switch>
      <Route exact path={['/en', '/fr']} component={HomePage} />
      <Route path={['/en/*', '/fr/*']}>
        <Route path="/:lang/*" component={DefaultLanguage} />

в том же файле (App.js) у нас есть такой компонент (с использованием response-localize-redux):

const DefaultLanguage = withLocalize(
  ({ activeLanguage, setActiveLanguage, ...props }) => {
    useEffect(() => {
      console.log('setting active language');
      setActiveLanguage(props.match.params.lang);
    }, []);
    return <></>;
  }
);

Проблема в том, что каждая ссылка, по которой я нажимаю, запускает setActiveLanguage, хотя я поставил [], чтобы он запускался только при первом рендеринге (потому что это единственный раз, когда я забочусь о настройке языка из URL-адреса). У меня была эта проблема и в других частях приложения. . Насколько я понимаю, useEffect не должен запускаться каждый раз, когда компонент монтируется, если только его зависимости не меняются, но, похоже, мне не хватает детали.


person Avedis Kiyici    schedule 17.05.2019    source источник


Ответы (1)


Вы правы в том, что передача пустого массива в useEffect остановит его выполнение при последующих рендерингах, но это не остановит его выполнение, если компонент будет размонтирован, а затем снова смонтирован.

Я предполагаю, что, нажимая на ваши ссылки, вы фактически размонтируете, а затем повторно монтируете свой DefaultLanguage компонент.

Вы можете проверить это, вернув функцию очистки из вашего useEffect хука.

Например,

useEffect(() => {
      console.log('setting active language');
      setActiveLanguage(props.match.params.lang);

      return () => console.log('Unmounting');
    }, []);

Если вы видите этот журнал, значит, вы нашли свою проблему.

Быстрое и грязное решение может заключаться в том, чтобы проверить, изменился ли язык, и, если да, установить его. Это не коснется потенциально ненужного монтирования / размонтирования, но, по крайней мере, позволит избежать повторной настройки языка.

useEffect(() => {
      if (activeLanguage !== props.match.params.lang) {
        console.log('setting active language');
        setActiveLanguage(props.match.params.lang);
      }
    }, []);
person RobertMcReed    schedule 18.05.2019
comment
Деталь, которую я упустил, - это разница между рендером и монтированием. Я не думал, что useEffect с [] снова запустится, несмотря ни на что. Это было очень полезно. - person Avedis Kiyici; 21.05.2019