![](/img/trans.png)
[英]Warning: Can't call setState (or forceUpdate) on an unmounted component in React Native
[英]React Warning: Can't call setState (or forceUpdate) on an unmounted component
我有两个组件:
订单 - 获取一些数据并显示它。
ErrorHandler - 如果服务器上发生一些错误,模态将显示并显示一条消息。
ErrorHandler 组件正在扭曲订单组件
我使用 axios 包在 Orders 组件中加载数据,我使用 axios 拦截器设置有关错误的状态,并在组件卸载后弹出。
当我前后导航到订单组件时,有时会在控制台中收到错误消息:
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)
我试图通过我之前的案例来解决它React Warning: Can only update amounted ormounting component但在这里我不能由检查员制作 axios 令牌。 以前有人解决过这个问题吗?
这是我的组件:
订单:
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);
错误处理程序:
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;
我认为这是由于触发 setState 的异步调用,即使未安装组件也可能发生。 为了防止这种情况发生,您可以使用某种标志:
state = {
isMounted: false
}
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);
return () => {
setIsMounted(false);
}
}, []);
return <div></div>;
}
export default Component;
您不能在 componentWillMount 方法中设置状态。 尝试重新考虑您的应用程序逻辑并将其移动到另一种生命周期方法中。
我认为根本原因与我昨天回答的相同,您需要在unmount
上“取消”请求,我不知道您是否正在为Orders
组件中的api.get()
调用执行此操作。
关于错误处理的说明,它看起来过于复杂,我绝对鼓励查看 React 提供的ErrorBoundaries 。 您不需要interceptors
或更高阶的组件。
对于 ErrorBoundaries,React 引入了一个名为: componentDidCatch
的生命周期方法。 您可以使用它来简化您的ErrorHandler
代码:
class ErrorHandler extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, info) {
this.setState({ hasError: true, errorMessage : error.message });
}
render() {
if (this.state.hasError) {
return <Modal
modalClosed={() => console.log('What do you want user to do? Retry or go back? Use appropriate method logic as per your need.')}>
{this.state.errorMessage ? this.state.errorMessage : null}
</Modal>
}
return this.props.children;
}
}
然后在您的Orders
组件中:
class Orders extends Component {
let cancel;
state = {
orders: [],
loading: true
}
componentDidMount() {
this.asyncRequest = api.get('/orders.json', {
cancelToken: new CancelToken(function executor(c) {
// An executor function receives a cancel function as a parameter
cancel = c;
})
})
.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 });
// please check the syntax, I don't remember if it is throw or throw new
throw error;
});
}
componentWillUnmount() {
if (this.asyncRequest) {
cancel();
}
}
render() {
return (
<div>
{this.state.orders.map(order => {
return (<Order
key={order.id}
ingrediencies={order.ingrediencies}
price={order.price} />);
})}
</div>
);
}
}
并在您的代码中使用它作为:
<ErrorHandler>
<Orders />
</ErrorHandler>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.