Предупреждение об установке setState в несмонтированном компоненте

Я получаю эту ошибку:

warning.js: 33 Предупреждение: невозможно вызвать setState (или forceUpdate) для несмонтированный компонент. Это неоперация, но это указывает на утечку памяти в вашем приложении. Чтобы исправить, отмените все подписки и асинхронные задачи в методе componentWillUnmount.

Но я не использую метод componentWillUnMount.

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

Здесь Маршрут:

<StyleRoute props={this.props} path="/account" component= 
{RequireAuth(Account)} />

где RequireAuth - это HOC. Здесь HOC:

 import { withRouter } from 'react-router';

export default function RequireAuth(Component) {

  return class AuthenticatedComponent extends React.Component {

    componentWillMount() {
      this.checkAuth();
    }

    checkAuth() {
      if ( ! this.props.isAuthenticated) {
        this.props.history.push('/');
      }
    }

    render() {
      return this.props.isAuthenticated
        ? <Component { ...this.props } />
        : null;
    }

  }

  return withRouter(AuthenticatedComponent);
}

Код работает как задумано, но я получаю эту ошибку, когда /account отображается. Как вы заметили, нигде в моем прямом коде нет метода componentWillUnMount. Я действительно в замешательстве, почему это предупреждение продолжает появляться, и любая информация поможет.


Обновление 23.05.18.

Чтобы избавиться от ошибки и пропустить реквизит, я сделал две вещи:

1) Я выбрал наличие двух функций более высокого порядка в родительском компоненте приложения вместо использования HOC. Одна функция более высокого порядка предназначена для передачи реквизита, а другая - для проверки подлинности. У меня были проблемы с передачей любого реквизита, кроме истории браузера, поэтому функция renderProps ниже.

renderProps = (Component, props) => {
  return (
      <Component {...props} />
    );
}

checkAuth = (Component, props) => {
    if (props.isAuthenticated) {
        return <Component {...props} />
    }
    if (!props.isAuthenticated) {
        return <Redirect to='/' />
    }
}

2) Чтобы использовать их, я должен был выполнить рендеринг пользователя в своем маршруте, в отличие от компонента.

//I could pass props doing this, sending them through the above functions
<Route exact path="/sitter-dashboard" render={ () => this.checkAuth(SitterDashboard, this.props) } />
<Route exact path={"/account/user"} render={() => this.renderProps(User, this.props)} />

//I couldn't pass props doing this
<Route {...this.props} exact path="/messages" component={Messages} />

Ниже приведена документация по компоненту "Маршрутизатор и против" как метод визуализации маршрута: https://reacttraining.com/react-router/web/api/Route/route-render-methods

Также здесь есть хорошее объяснение Кару

Наконец, я использовал этот код из документации по React Router 4 в качестве шаблона для того, что я делал выше. Я уверен, что приведенное ниже чище, но я все еще учусь, и то, что я сделал, имеет для меня немного больше смысла.

const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
  {...rest}
  render={props =>
  fakeAuth.isAuthenticated ? (
       <Component {...props} />
      ) : (
        <Redirect
          to={{
            pathname: "/login",
            state: { from: props.location }
          }}
        />
      )
    }
  />
);

Ответ 1

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

Хорошей практикой для выявления подобных ошибок является отрисовка потока вашего приложения и выяснение того, когда вы звоните setState.

Еще одна вещь, которую я бы изменил на вашем месте, это componentDidMount вместо componentWillMount, чтобы проверить некоторые данные. Примите во внимание, что fb не поддерживает эту функциональность.

Этот жизненный цикл ранее назывался componentWillMount. Это имя будет работать до версии 17. Используйте кодовый код rename-unsafe-lifecycles для автоматического обновления ваших компонентов.

Reactjs component documentation

Ответ 2

У меня была похожая проблема, но я выяснил причину того же самого, так что вот фрагмент кода, где я столкнулся с этой ошибкой.

Warning: Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.

Причина:

   this.setState({ showLoader: true });
    const { username } = this.state;
    const URL = 'https://api.github.com/users/${username}';
    try {
      const { data } = await axios(URL);
      this.props.apiData(data);
      this.props.history.push("profile");
    } catch (e) {
      console.error(e);
    }
    this.setState({ showLoader: false });

Как вы можете видеть в фрагменте кода, я делал

this.props.history.push("profile");

перед установкой состояния.

this.setState({ showLoader: false });

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

Решение:

Размещая

this.setState({ showLoader: false });

над this.props.history.push("profile"); решил проблему.

Надеюсь, это поможет.