我认为标题说明了一切.每次卸载仍在提取的组件时都会显示黄色警告. 安慰 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 thecomponentWillUnmount
method.
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