Предупреждение об установке 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");
решил проблему.
Надеюсь, это поможет.