无法在已卸载的组件上执行React状态更新。 React,redux和useEffect的问题

时间:2019-11-25 10:29:27

标签: reactjs redux react-redux axios react-hooks

我有一个使用如下钩子的React组件:

const myComponent = (props) => {
  useEffect(() => {
     FetchData()
     .then(data => {
       setState({data: data});
     }
    // some other code
  }, []);

//some other code and render method...
}

fetchData负责使用axios并从API获取数据:

const FetchData = async () => {
   try {
    res = await myApiClient.get('/myEndpoint);
   } catch (err) {
    console.log('error in FetchData');
    res = err.response
}
}

,最后在外部定义myApiClient。我必须使用此设置才能使用不同的API ...

import axios from "axios";
axios.defaults.headers.post["Content-Type"] = "application/json";

const myApiClient = axios.create({
  baseURL: process.env.REACT_APP_API1_BASEURL
});
const anotherApiClient = axios.create({
  baseURL: process.env.REACT_APP_API2_BASEURL
});

export {
  myApiClient,
  anotherApiClient
};

使用此设置,我会收到警告

Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

我在Google上进行了一些搜索,并看到了一些有关如何清理useEffect中的请求的建议,例如this,但我的axios是在外部定义的。那么如何使用此设置发送取消通知?

此外,应用程序正在使用redux,不确定是否以某种方式涉及到它。

欢迎其他避免错误的建议。

2 个答案:

答案 0 :(得分:1)

您可以为此使用defer中的rxjs

const FetchData = () => {
  try {
    return myApiClient.get("/myEndpoint");
  } catch (err) {
    console.log("error in FetchData");
    return err.response;
  }
};

const myComponent = (props) => {
  useEffect(() => {
    const subscription = defer(FetchData()).subscribe({
      next: ({
        data
      }) => {
        setState({
          data: data
        });
      },
      error: () => {
        // error handling
      },
      complete: () => {
        // cancel loading state etc
      }
    });

    return () => subscription.unsubscribe();
  }, []);
}

答案 1 :(得分:0)

始终检查您是否正在处理提取或任何长时间的操作。

let _isMounted = false;

const HooksFunction = props => {


  const [data, setData] = useState({}); // data supposed to be object

  const fetchData = async ()=> {
    const res = await myApiClient.get('/myEndpoint');
    if(_isMounted) setData(res.data); // res.data supposed to return an object
  }

  useEffect(()=> {

    _isMounted = true;

    return ()=> {
        _isMounted = false;
    }

  },[]);

  return (
    <div>
      {/*....*/}
    <div/>
  );

}