UseCookies из реагирующих файлов cookie вызывает цикл рендеринга

У меня есть код, который работал раньше, но после того, как я обновил все библиотеки, он начал непрерывно отображать компонент приложения, и React выдает ошибку бесконечного цикла рендеринга: Minified React error # 185.

Вот мой код:

import React from 'react';
import { CookiesProvider, useCookies } from 'react-cookie';
import { withTranslation } from 'react-i18next';
import { connect } from 'react-redux';

import store from './redux/store';

import { getUserDetailsByToken } from './redux/actions/user-actions';

const AUTHENTICATION_COOKIE = 'authat';

function App(props) {
  const { i18n, userDetailsLoaded } = props;
  const [cookies] = useCookies([AUTHENTICATION_COOKIE]);

  if (cookies[AUTHENTICATION_COOKIE] && !userDetailsLoaded) {
    store.dispatch(getUserDetailsByToken());
  }

  i18n.changeLanguage('en');

  return (
    <CookiesProvider>
      <div className = "app">
        <Header />
        <main className = "app-content full-height">
          ...
        </main>
      </div>
    </CookiesProvider>
  );
}

function mapStateToProps(state) {
  return {
    userDetailsLoaded: state.userReducers.userDetailsLoaded,
  };
}

export default connect(mapStateToProps)(App);

Я попытался добавить флаг, чтобы вызывать функцию хранилища только один раз, учитывая, что сбор сведений о пользователе приведет к повторному рендерингу, но это не сработало.

Также я безуспешно закомментировал всю проверку файлов cookie.

Если я попытаюсь закомментировать строку const [cookies] = useCookies([AUTHENTICATION_COOKIE]);, и она перестанет бесконтрольно отображаться, это означает, что мне понадобится другой способ проверки файлов cookie при запуске приложения.

🤔 А знаете ли вы, что...
React использует компонентную архитектуру для организации кода.


117
1

Ответ:

Решено

Вызовы store.dispatch(getUserDetailsByToken()); и i18n.changeLanguage('en'); являются побочными эффектами и должны быть частью рендеринга.

Когда вы вызываете store.dispatch(getUserDetailsByToken());, он, вероятно, запускает процесс, вызывающий повторный рендеринг, который снова запускает отправку и так далее...

Кроме того, вам следует использовать хуки React-Redux useDispatch и useSelector вместо того, чтобы обертывать компонент connect HoC и получать dispatch путем импорта магазина.

import React from 'react';
import { CookiesProvider, useCookies } from 'react-cookie';
import { withTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';

import { getUserDetailsByToken } from './redux/actions/user-actions';

const AUTHENTICATION_COOKIE = 'authat';

function App(props) {
  const dispatch = useDispatch();
  const userDetailsLoaded = useSelector(state => state.userReducers.userDetailsLoaded);
  const { i18n } = props;
  const [cookies] = useCookies([AUTHENTICATION_COOKIE]);
  
  const authCookie = cookies[AUTHENTICATION_COOKIE];
  
  // an effect that gets called on mount or whenever authCookie or userDetailsLoaded change
  useEffect(() => {
    if (cookies[AUTHENTICATION_COOKIE] && !userDetailsLoaded) {
      dispatch(getUserDetailsByToken());
    }
  }, [dispatch, authCookie, userDetailsLoaded]);

  // a one time effect on mount
  useEffect(() => {
    i18n.changeLanguage('en');
  }, []);

  return (
    <CookiesProvider>
      <div className = "app">
        <Header />
        <main className = "app-content full-height">
          ...
        </main>
      </div>
    </CookiesProvider>
  );
}

export default App;

Интересные вопросы для изучения