小编典典

如何取消对componentWillUnmount的提取

reactjs

我认为标题说明了一切。每当我卸载仍在读取的组件时,都会显示黄色警告。

安慰

警告:无法在未安装的组件上调用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);
      });
  }

阅读 259

收藏
2020-07-22

共1个答案

小编典典

当您触发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实现所做的一样)。

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

2020-07-22