我认为标题说明了一切。每当我卸载仍在读取的组件时,都会显示黄色警告。
安慰
警告:无法在未安装的组件上调用setState(或forceUpdate)。这是一项禁忌措施,但是…若要修复,请取消方法中的所有订阅和异步任务componentWillUnmount。
setState
forceUpdate
componentWillUnmount
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时,它可能需要花费几秒钟的时间才能解决,到那时,用户可能已经导航到应用程序中的另一个位置。因此,setState在未安装的组件上执行Promise resolves时,您会得到一个错误-就像您的情况一样。这也可能导致内存泄漏。
这就是为什么最好将某些异步逻辑移出组件。
否则,您将需要以某种方式取消Promise。另外,作为一种不得已的技术(这是一种反模式),您可以保留一个变量来检查组件是否仍处于安装状态:
componentDidMount(){ this.mounted = true; this.props.fetchData().then((response) => { if(this.mounted) { this.setState({ data: response }) } }) } componentWillUnmount(){ this.mounted = false; }
我会再次强调-这是一种反模式,但在您的情况下可能就足够了(就像他们对Formik实现所做的一样)。
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其行为类似于类的静态属性,这意味着它的值更改时不会使组件重新呈现:
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