Предупреждение: Не удается обновить компонент при отображении другого компонента. Реактредукс.Потребитель

#reactjs #react-redux #react-hooks

Вопрос:

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

В предупреждении говорится:

index.js:1 Предупреждение: Не удается обновить компонент ( Connect(TabMenuComponent) ) при отображении другого компонента ( ReactRedux.Consumer ). Чтобы найти неправильный вызов setState() внутри ReactRedux.Consumer , следуйте трассировке стека, как описано в https://reactjs.org/link/setstate-in-render

Трассировка стека далее указывает мне на этот файл. Он указывает на строку 30, которая является строкой магазина.отправка:

 export const AuthRoute = ({ component: Component, roles, computedMatch, ignoreRedirection, ...rest }) => (
  <Route exact {...rest} render={props => {
    return <ReactReduxContext.Consumer>
      {({ store }) => {
        const user = store.getState().appData.user;

        if (!user) {
          auth.setRedirectUrl(window.location.pathname);
          return <Redirect to={auth.loginUrl} />;
        }

        const redirectUrl = auth.getRedirectUrl();

        if (redirectUrl amp;amp; !ignoreRedirection) {
          auth.removeRedirectUrl();
          return <Redirect to={redirectUrl} />;
        }

        if (roles amp;amp; roles.length amp;amp; !roles.some(neededRole => user.roles.some(userRole => userRole === neededRole))) {
          return <BaseLayout authError={stringKeys.error.unauthorized}></BaseLayout>;
        }

        store.dispatch({ type: "ROUTE_CHANGED", url: computedMatch.url, path: computedMatch.path, params: computedMatch.params })
        return <Component {...props} />;

      }}
    </ReactReduxContext.Consumer>;
  }
  } />
);
 

Ответ №1:

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

С оболочкой компонента класса:

 class CompWithDispatch extends React.Component {
   componentDidMount()  {
    const { store, type, url, path, params } = this.props;
    store.dispatch({ type, url, path, params })
   }

   render() {
      const { store, type, url, path, params , component: Component,  ...rest} = this.props;
      return <Component {...rest} />
   }
}
 
 

С оболочкой функционального компонента

 const CompWithDispatch = (props) => {
    const { store, type, url, path, params, component:Component, ...rest } = props;
    useEffect(() => {
       store.dispatch({ type, url, path, params })
    }, []);
    return <Component {...rest} />

}
 

и используйте его, как

 export const AuthRoute = ({ component, roles, computedMatch, ignoreRedirection, ...rest }) => (
  <Route exact {...rest} render={props => {
    return <ReactReduxContext.Consumer>
      {({ store }) => {
        const user = store.getState().appData.user;

        if (!user) {
          auth.setRedirectUrl(window.location.pathname);
          return <Redirect to={auth.loginUrl} />;
        }

        const redirectUrl = auth.getRedirectUrl();

        if (redirectUrl amp;amp; !ignoreRedirection) {
          auth.removeRedirectUrl();
          return <Redirect to={redirectUrl} />;
        }

        if (roles amp;amp; roles.length amp;amp; !roles.some(neededRole => user.roles.some(userRole => userRole === neededRole))) {
          return <BaseLayout authError={stringKeys.error.unauthorized}></BaseLayout>;
        }

        const additionalProps = { type: "ROUTE_CHANGED", url: computedMatch.url, path: computedMatch.path, params: computedMatch.params })
        return <CompWithDispatch {...additionalProps} {...props} component={component}/>;

      }}
    </ReactReduxContext.Consumer>;
  }
  } />
);