我想这个标题说明了一切.每次卸载仍在提取的组件时,都会显示黄色警告.

Console

警告:无法对未安装的组件调用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 时,可能需要几秒钟时间才能解决问题,到那时,用户可能已经导航到了你应用程序中的另一个地方.所以,当Promise resolves setState在未安装的组件上执行时,您会得到一个错误——就像您的情况一样.这也可能导致内存泄漏.

That's why it is best to move some of your asynchronous logic out of components.

否则,你将需要以某种方式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的类似讨论

EDIT:

这可能就是我如何用Hooks解决同样的问题(除了react 之外什么都没有):

OPTION 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;
}

OPTION 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

Reactjs相关问答推荐

CSS转换不适用于React MUI对象

当我在React中使用类方法更新模型的状态时,它在严格模式下触发两次

react-hook-form问题:为什么getValues不返回大多数当前值?

cypress 不能点击SPAN

值在返回页面时不更新,即使我已经更新了它们

防止在Reaction中卸载

React,React Router,Joy UI:如何在导航离开和返回后禁用snackbar重新出现?

如何修复ReferenceError:在构建过程中未定义导航器

如何测试根据 prop 更改 CSS 属性的 useEffect 钩子?

React Context API 在 Next.js 中更改路由时获取默认数据

无法从子组件传递数据到父组件

将水平滚动视图添加到底部导航选项卡

文本的几个词具有线性渐变 colored颜色 - React native

在react 中从外部 api 渲染列表

我可以更改 styled() 中的响应吗? (MUI v5)

如何在同一路由路径上重新渲染组件(链接,V6)reactjs

无法读取未定义的react native 的属性参数

setState 改变对象引用

使用 React、Redux 和 Firebase 的无限循环

将鼠标悬停在仅适用于该类的第一个实例的 p5.js 类上