我发现此错误:
无法在已卸载的组件上调用setState(或forceUpdate)。这是空操作,但它表明应用程序中发生内存泄漏。要解决此问题,请在componentWillUnmount方法中取消所有订阅和异步任务。
上下文:当我连接时,我在主页上,该页面上不包含面包屑,但是如果我继续CampaignPage
(也是组件的名称),则我有BreadCrumb
(组件名称)发现此错误。
在我看到的另一篇文章中,他们说可能是ComponentWillMount
异步问题,但我认为我的问题有所不同,我找不到解决方案。
我的代码如下所示:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import classnames from 'classnames';
import objectAssign from 'object-assign';
import { withRouter } from 'react-router';
import {
BREADCRUMBS_ROUTES,
BREADCRUMBS_ROUTES_FOR_ID,
BREADCRUMBS_ENDPOINT
} from 'constants';
import { getEntityById, setUpdatedBreadcrumbs } from 'actions/breadcrumbs';
import style from './style.scss';
class Breadcrumbs extends Component {
constructor(props) {
super(props);
this.state = {
breadcrumbs: [],
names: {}
};
this.setBreadcrumbs = this.setBreadcrumbs.bind(this);
this.loadEntityNameById = this.loadEntityNameById.bind(this);
}
componentWillMount() {
this.setBreadcrumbs();
}
componentWillReceiveProps(nextProps) {
const { isWillUpdate: newIsWillUpdate } = nextProps;
const { isWillUpdate, saveUpdatedBreadcrumbs } = this.props;
if (isWillUpdate === false && newIsWillUpdate === true) {
this.setBreadcrumbs();
saveUpdatedBreadcrumbs();
}
}
setBreadcrumbs() {
const { params, path } = this.props.match;
let currentPath = '';
const pathSplitedAndExtendet = path.split('/')
.filter(item => !!item)
.map(item => {
if (item[0] === ':' && item.slice(1) !== 'adPage') {
const parameterName = item.slice(1);
this.loadEntityNameById(
parameterName,
params[parameterName]
);
return {
route: `/${params[parameterName]}${BREADCRUMBS_ROUTES_FOR_ID[parameterName]}`,
parameter: parameterName
};
}
return {
route: `/${item}`,
parameter: ''
};
});
const breadcrumbs = pathSplitedAndExtendet
.filter(item => item.parameter !== 'adPage')
.map((item) => {
const indexOfRoute = currentPath.indexOf(item.route);
if (currentPath.slice(indexOfRoute) !== item.route) {
currentPath = `${currentPath}${item.route}`;
}
return ({
...item,
name: BREADCRUMBS_ROUTES[item.route] || '',
route: currentPath
});
});
this.setState({ breadcrumbs });
}
async loadEntityNameById(parameter, id) {
const { loadEntityById } = this.props;
await loadEntityById(BREADCRUMBS_ENDPOINT[parameter], id)
.then((data) => {
this.setState({ names: objectAssign(this.state.names, { [parameter]: { id, name: data.name } }) });
});
}
render() {
const { breadcrumbs, names } = this.state;
const { showBreadcrumbs } = this.props;
return (
<div className={style.breadcrumbs}>
{
showBreadcrumbs && breadcrumbs
.map((item, index) => {
return (
<div
key={`${item.name}--${item.route}--${index}`}
className={classnames(style.bread, index === breadcrumbs.length - 1 ? style.last : null)}
role="link"
tabIndex={-10 - index}
onKeyDown={() => {}}
onClick={item.route ? () => this.props.history.push(item.route) : null}
>
{`${item.name || (names[item.parameter]
? names[item.parameter].name : '...')}
${((breadcrumbs.length > 1) && (index !== breadcrumbs.length - 1)) ? ' >' : ''}
`}
</div>
);
})
}
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(withRouter(Breadcrumbs));
最佳答案
无法在已卸载的组件上调用setState(或forceUpdate)。这是空操作,但它表明应用程序中发生内存泄漏。要解决此问题,请在componentWillUnmount方法中取消所有订阅和异步任务。
此错误消息明确指出您的应用程序存在内存泄漏。到底是怎么回事?
好吧,您正在setBreadcrumbs
方法中使用异步操作(loadEntityNameById)。在componentWillMount
和componentWillReceiveProps
中调用哪个。这意味着当您从CampaignPage
组件转到BreadCrumb
组件时,它将执行异步操作,即。 loadEntityNameById
在后台运行,仅在完成后设置状态。但是直到那时,您的BreadCrumb
组件都可能已卸载。 react应用程序不允许您更新未安装组件的状态。
此外,您根本不应使用componentWillMount
方法。请使用componentDidMount
挂钩。
要解决此问题,您可以设置一个标志,例如:
componentDidMount() {
// component is mounted, set the didMount property on BreadCrumb component
// you can use any name instead of didMount what you think is proper
this.didMount = true
// now, you can update the state
if(this.didMount) { // be sure it's not unmounted
this.setState({names: ...})
}
接下来,在卸载组件时,应清除didMount属性。
componentWillUnmount() {
this.didMount = false // component is unmounted
这将确保您不会泄漏应用程序内存。因为,我们在需要时正确设置了状态,而在不需要时则设置了状态,并停止了不必要的循环。