反应警告:无法在未安装的组件上调用 setState(或 forceUpdate) [英] React Warning: Can't call setState (or forceUpdate) on an unmounted component

查看:19
本文介绍了反应警告:无法在未安装的组件上调用 setState(或 forceUpdate)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个组件:
订单 - 获取一些数据并显示它.
ErrorHandler - 如果服务器上发生一些错误,模态将显示并显示一条消息.
ErrorHandler 组件正在扭曲订单组件

我使用 axios 包加载 Orders 组件中的数据,我使用 axios 拦截器设置有关错误的状态,并在组件卸载后弹出.

当我前后导航到订单组件时,有时会在控制台中收到错误消息:

警告:无法在未安装的组件上调用 setState(或 forceUpdate).这是一个空操作,但它表明您的应用程序中存在内存泄漏.要修复,请取消 componentWillUnmount 方法中的所有订阅和异步任务.在订单中(在 ErrorHandler.jsx:40)在辅助中(在 ErrorHandler.jsx:34)在 _class2(由 Route 创建)

我试图通过我之前的案例来解决它反应警告:只能更新已安装或正在安装的组件,但在这里我无法通过检查员制作 axios 令牌.以前有人解决过这个问题吗?

这是我的组件:

订单:

import React, { Component } from 'react';从 '../../api/api' 导入 api;从'../../components/Order/Order/Order'导入订单;从'../../hoc/ErrorHandler/ErrorHandler'导入ErrorHandler;类订单扩展组件{状态 = {命令: [],加载:真实}componentDidMount() {api.get('/orders.json').then(响应 => {const fetchedOrders = [];如果(响应&& response.data){for (let key in response.data) {fetchedOrders.push({身份证:钥匙,...响应.数据[键]});}}this.setState({ loading: false, orders: fetchedOrders });}).catch(错误=> {this.setState({loading: false });});}使成为() {返回 (<div>{this.state.orders.map(order => {返回(<订单键={订单.id}配料={订单.配料}价格={订单.价格}/>);})}

);}}导出默认的 ErrorHandler(Orders, api);

错误处理程序:

import React, { Component } from 'react';从'../Auxiliary/Auxiliary'导入辅助;从../../components/UI/Modal/Modal"导入模态;const ErrorHandler = (WrappedComponent, api) =>{返回类扩展组件{requestInterceptors = null;responseInterceptors = null;状态 = {错误:空};componentWillMount() {this.requestInterceptors = api.interceptors.request.use(request => {this.setState({ 错误: null });退货请求;});this.responseInterceptors = api.interceptors.response.use(response => response, error => {this.setState({ 错误: 错误 });});}componentWillUnmount() {api.interceptors.request.eject(this.requestInterceptors);api.interceptors.response.eject(this.responseInterceptors);}errorConfirmedHandler = () =>{this.setState({ 错误: null });}使成为() {返回 (<辅助><模态显示={this.state.error}modalClosed={this.errorConfirmedHandler}>{this.state.error ?this.state.error.message : null}</模态><WrappedComponent {...this.props}/></辅助>);}};};导出默认的 ErrorHandler;

解决方案

我认为这是由于异步调用触发了 setState,即使组件未安装也可能发生.为了防止这种情况发生,您可以使用某种标志:

 状态 = {isMounted: 假}componentDidMount() {this.setState({isMounted: true})}componentWillUnmount(){this.state.isMounted = false}

然后用 if 包装你的 setState 调用:

if (this.state.isMounted) {this.setState({ loading: false, orders: fetchedOrders });}

编辑 - 添加功能组件示例:

function Component() {const [isMounted, setIsMounted] = React.useState(false);useEffect(() => {setIsMounted(true);返回 () =>{setIsMounted(false);}}, []);返回<div></div>;}导出默认组件;

I have 2 components:
Orders - fetch some data and display it.
ErrorHandler - In case some error happen on the server, a modal will show and display a message.
The ErrorHandler component is warping the order component

I'm using the axios package to load the data in the Orders component, and I use axios interceptors to setState about the error, and eject once the component unmounted.

When I navigate to the orders components back and forward i sometimes get an error in the console:

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.
    in Orders (at ErrorHandler.jsx:40)
    in Auxiliary (at ErrorHandler.jsx:34)
    in _class2 (created by Route)

I tried to solve it by my previous case React Warning: Can only update a mounted or mounting component but here I can't make an axios token by the inspectors. Has anyone solved this issue before?

Here are my components:

Orders:

import React, { Component } from 'react';
import api from '../../api/api';
import Order from '../../components/Order/Order/Order';
import ErrorHandler from '../../hoc/ErrorHandler/ErrorHandler';

class Orders extends Component {
    state = {
        orders: [],
        loading: true
    }

    componentDidMount() {
        api.get('/orders.json')
            .then(response => {
                const fetchedOrders = [];
                if (response && response.data) {
                    for (let key in response.data) {
                        fetchedOrders.push({
                            id: key,
                            ...response.data[key]
                        });
                    }
                }
                this.setState({ loading: false, orders: fetchedOrders });
            })
            .catch(error => {
                this.setState({ loading: false });
            });
    }

    render() {
        return (
            <div>
                {this.state.orders.map(order => {
                    return (<Order
                        key={order.id}
                        ingrediencies={order.ingrediencies}
                        price={order.price} />);
                })}
            </div>
        );
    }
}

export default ErrorHandler(Orders, api);

ErrorHandler:

import React, { Component } from 'react';
import Auxiliary from '../Auxiliary/Auxiliary';
import Modal from '../../components/UI/Modal/Modal';

const ErrorHandler = (WrappedComponent, api) => {
    return class extends Component {
        requestInterceptors = null;
        responseInterceptors = null;
        state = {
            error: null
        };

        componentWillMount() {
            this.requestInterceptors = api.interceptors.request.use(request => {
                this.setState({ error: null });
                return request;
            });
            this.responseInterceptors = api.interceptors.response.use(response => response, error => {
                this.setState({ error: error });
            });
        }

        componentWillUnmount() {
            api.interceptors.request.eject(this.requestInterceptors);
            api.interceptors.response.eject(this.responseInterceptors);
        }

        errorConfirmedHandler = () => {
            this.setState({ error: null });
        }

        render() {
            return (
                <Auxiliary>
                    <Modal
                        show={this.state.error}
                        modalClosed={this.errorConfirmedHandler}>
                        {this.state.error ? this.state.error.message : null}
                    </Modal>
                    <WrappedComponent {...this.props} />
                </Auxiliary>
            );
        }
    };
};

export default ErrorHandler;

解决方案

I think that's due to asynchronous call which triggers the setState, it can happen even when the component isn't mounted. To prevent this from happening you can use some kind of flags :

  state = {
    isMounted: false
  }
  componentDidMount() {
      this.setState({isMounted: true})
  }
  componentWillUnmount(){
      this.state.isMounted = false
  }

And later wrap your setState calls with if:

if (this.state.isMounted) {
   this.setState({ loading: false, orders: fetchedOrders });
}

Edit - adding functional component example:

function Component() {
  const [isMounted, setIsMounted] = React.useState(false);

  useEffect(() => {
    setIsMounted(true);
    return () => {
      setIsMounted(false);
    }
  }, []);

  return <div></div>;
}

export default Component;

这篇关于反应警告:无法在未安装的组件上调用 setState(或 forceUpdate)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆