简体   繁体   中英

useEffect cleanup function in react

I get this warning '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.'

Code

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

The data is fetched but I could'nt figure what to add in the clean up. Any suggestions?

Issue

The problem is that the fetch request resolves but the component has unmounted ( for some reason ) and so the state update can't occur now.

Solution

You need to use an Abort Controller to cancel in-flight requests. If the component unmounts, an effect cleanup function cancels the fetch request.

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
}, []);

Note: When abort() is called, the fetch() promise rejects with an AbortError .

You will likely need to catch this promise rejection somewhere. You can append a .catch block to the Promise chain.

  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);

try the following code:

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

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM