0

This is in a functional component.

I have a submit() function that looks like so:

  async function handleSubmit(event) {
    event.preventDefault();
    try {
      let resp = await fetch("FOOBAR/BAX", {
        method: 'POST',
        body: JSON.stringify({ /*stuff*/})
      });
      if (resp.ok){
        // yadda yadda yadda
        props.history.push("/"); // navigate
      }
    } 
  } 

Now, when I cause navigation to occur I'm getting the dreaded 'Can't perform a React state update on an unmounted component.' error.

So, using effects, how do I make sure this fetch call is cleaned up? All the examples I'm seeing use useEffect to both set up and then cleanup the call (with cleanup function).

4
  • 3
    It doesn't look like there's any state change in your handleSubmit function. I don't see anything to clean here. Would you care to share more code, maybe on stackblitz? Commented Jan 4, 2020 at 21:55
  • @yonki Thanks, maybe my assumption is wrong. Commented Jan 4, 2020 at 21:57
  • @yonki let's say I want to make sure that request is cancelled -- how would I useEffect to do that? Commented Jan 4, 2020 at 22:21
  • 2
    @mtyson I believe @yonki is informing you that the error doesn't match the code you shared. Your handleSubmit function doesn't appear to update state (unless it is hidden within the yadda yadda yadda bit). About using useEffect hook to cancel a fetch request you can use an abort controller with the fetch request. Let us know if you need help with that. In the mean time , as yonki requested, can you share more of the component code or share a link to it in stackblitz or codesandbox? Commented Jan 4, 2020 at 23:58

1 Answer 1

1

Clean up a fetch request by cancelling on dismount using an abort controller

Factor the fetch request logic out of the handler into the effect hook and use a state hook to trigger the effect to fire. Return the controller's abort function in the effect hook to be called when the component unmounts.

const [body, setBody] = useState('');

useEffect(() => {
  const controller = new AbortController();
  const signal = controller.signal;

  if (body) {
    fetch("FOOBAR/BAX", {
      method: 'POST',
      body: JSON.stringify(body),
      signal, // add signal to request
    })
    .then(res => {
      setBody(''); // clear request body value
      if (res.ok) props.history.push('/');
    });
  }

  return controller.abort; // return the abort function to be called when component unmounts
}, [body]);

const handleSubmit = (event) => {
  event.preventDefault();
  setBody({ /*stuff*/ }); // set request body value to trigger effect to fetch
};

Here's a codesandbox with this implemented as a react hook, with manual abort and automatic abort on unmounting.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.