我认为标题说明了一切.每次卸载仍在提取的组件时都会显示黄色警告. 安慰 Warning: Can’t call setState (or forceUpdate ) on an unmounted component. This is a no-op, but … To fix, cancel all subscriptions and as
安慰
Warning: Can’t call
setState(orforceUpdate) on an unmounted component. This is a no-op, but … To fix, cancel all subscriptions and asynchronous tasks in thecomponentWillUnmountmethod.
constructor(props){
super(props);
this.state = {
isLoading: true,
dataSource: [{
name: 'loading...',
id: 'loading',
}]
}
}
componentDidMount(){
return fetch('LINK HERE')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
当您触发Promise时,它可能需要几秒钟才能结算,到那时用户可能已导航到您应用中的其他位置.因此,当Promise解析setState在未安装的组件上执行时,您会收到错误 – 就像您的情况一样.这也可能导致内存泄漏.
这就是为什么最好将一些异步逻辑从组件中移出.
否则,您将需要以某种方式cancel your Promise.或者 – 作为最后的手段技术(它是反模式) – 您可以保留一个变量来检查组件是否仍然挂载:
componentDidMount(){
this.mounted = true;
this.props.fetchData().then((response) => {
if(this.mounted) {
this.setState({ data: response })
}
})
}
componentWillUnmount(){
this.mounted = false;
}
我将再次强调 – 这是is an antipattern,但在你的情况下可能就足够了(就像他们在Formik实施时所做的那样).
关于GitHub的类似讨论
编辑:
这可能是我如何用Hooks解决同样的问题(只有React):
选项A:
import React, { useState, useEffect } from "react";
export default function Page() {
const value = usePromise("https://something.com/api/");
return (
<p>{value ? value : "fetching data..."}</p>
);
}
function usePromise(url) {
const [value, setState] = useState(null);
useEffect(() => {
let isMounted = true; // track whether component is mounted
request.get(url)
.then(result => {
if (isMounted) {
setState(result);
}
});
return () => {
// clean up
isMounted = false;
};
}, []); // only on "didMount"
return value;
}
选项B:或者使用useRef,其行为类似于类的静态属性,这意味着它在值改变时不会使组件重新呈现:
function usePromise2(url) {
const isMounted = React.useRef(true)
const [value, setState] = useState(null);
useEffect(() => {
return () => {
isMounted.current = false;
};
}, []);
useEffect(() => {
request.get(url)
.then(result => {
if (isMounted.current) {
setState(result);
}
});
}, []);
return value;
}
// or extract it to custom hook:
function useIsMounted() {
const isMounted = React.useRef(true)
useEffect(() => {
return () => {
isMounted.current = false;
};
}, []);
return isMounted; // returning "isMounted.current" wouldn't work because we would return unmutable primitive
}
示例:https://codesandbox.io/s/86n1wq2z8
