反应中的 useEffect 清理功能

时间:2021-01-01 10:39:27

标签: reactjs react-hooks

我收到此警告“无法对已卸载的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要修复,请取消 useEffect 清理函数中的所有订阅和异步任务。'

<块引用>

代码

 const [photo, setPhoto] = useState([]);
 useEffect(() => {
 fetch('/mypost', {
  headers: {
    cookie: 'access_token',
  },
})
  .then((res) => res.json())
  .then((data) => {
    setPhoto(data.mypost);
  });
}, []);

数据已获取,但我不知道要在清理中添加什么。有什么建议吗?

3 个答案:

答案 0 :(得分:3)

问题

问题是获取请求已解决,但组件已卸载(出于某种原因),因此现在无法进行状态更新。

解决方案

您需要使用 Abort Controller 取消进行中的请求。如果组件卸载,效果清除函数会取消获取请求。

useEffect(() => {
  const controller = new AbortController(); // <-- create controller
  const { signal } = controller; // <-- get signal for request

  fetch('/mypost', {
    headers: {
      cookie: 'access_token',
    },
    signal, // <-- pass signal with options
  })
    .then((res) => res.json())
    .then((data) => {
      setPhoto(data.mypost);
    });

  return () => controller.abort(); // <-- return cleanup function to abort
}, []);
<块引用>

注意:当调用 abort() 时,fetch() 承诺会拒绝 AbortError

您可能需要在某处捕获此承诺拒绝。您可以将 .catch 块附加到 Promise 链。

  fetch('/mypost', {
    headers: {
      cookie: 'access_token',
    },
    signal, // <-- pass signal with options
  })
    .then((res) => res.json())
    .then((data) => {
      setPhoto(data.mypost);
    })
    // catch any rejected fetch promises (including aborted fetches!)
    .catch(console.error);

答案 1 :(得分:1)

Generic JSON fetch demo

import React, {useState} from "react";
import { useAsyncEffect } from "use-async-effect2";
import cpFetch from "cp-fetch";

export default function TestComponent(props) {
  const [photo, setPhoto] = useState([]);

  useAsyncEffect(
    function* () {
      const response = yield cpFetch('/mypost');
      setPhoto((yield response.json()).mypost);
    },
    []
  );

  return <div></div>;
}

答案 2 :(得分:0)

试试下面的代码:

 useEffect(() => {
let isMounted = true;
 fetch('/mypost', {
  headers: {
    cookie: 'access_token',
  },
})
  .then((res) => res.json())
  .then((data) => {
    if (isMounted)  setPhoto(data.mypost);
  });

//cleanup function
rreturn () => { isMounted = false };
    
}, []);