🎁 The Js-Craft Guide to React is now available with a 30% off discount!

Optimizing React useEffect: preventing multiple API calls (fetch race conditions)

Race conditions while doing multiple sequential API calls in React useEffect() can cause some strange behaviors and performance issues.

Let's take the below code:

const App = () => {
    const [id, setId] = useState(1)

    const handleClick = ()=> setId(prev => prev + 1)

    return <div>
        <button onClick={handleClick}>Next</button>
        <Article id={id} />
    </div>
}

const Article = ({id}) => {
    const [text, setText] = useState('')

    useEffect(()=> {
        fetch('https://jsonplaceholder.typicode.com/posts/' + id)
            .then( resp => resp.json())
            .then( resp => setText(resp.body))
    }, [id])

    return (<div>{text}</div>)
}

We just fetch a new article at the press of a button.

While this works great at first glance, things will break if the user presses the Get Next Article button very fast multiple times.

To make it easier to spot you can set up slow 3G mode in the developer's tools.

React useEffect: preventing multiple API calls fetch race conditions

This is quite a common problem as we get multiple chained API calls in useEffect() and therefore we end up with a race condition.

One alternative to fix this issue is by using a boolean value, as described in this video.

While this works, I think a nicer approach will be to use a Javascript AbortController, to cancel the ongoing API calls.

const {useState, useEffect} = React

const App = () => {
    const [id, setId] = useState(1)
    const handleClick = ()=> setId(prev => prev + 1)
    return <div>
        <Article id={id} />
        <button onClick={handleClick}>Get Next Article</button>
    </div>
}

const Article = ({id}) => {
    const [text, setText] = useState('')

    useEffect(()=> {
        const abortCtrl = new AbortController()
        const fetchOtps = {signal: abortCtrl.signal}
        fetch('https://jsonplaceholder.typicode.com/posts/' + id, 
            {signal: abortCtrl.signal})
                .then( resp => resp.json())
                .then( resp => setText(resp.body))

        // the cleanup function runs 
        // each time useEffect() is exectued
        return () => abortCtrl.abort()
    }, [id])

    return (<div>{text}</div>)
}

The cleanup function of useEffect() is called, not only when the component is unmounted but also at each new run of useEffect().

With this approach we avoid the text flickering, but we also drop any ongoing fetch requests.

I hope you will find this useful. As usual, you can check out the full code on my Github and the running example here.

10 Javascript AI projects with Langchain & React

Not sure what to build? Dive in with these Javascript AI projects! Learn how to build LLM powered apps using Langchain.js and React! Connect your apps to LLMs such as OpenAI, create agents, use vector databases, or setup AI context.

10 Javascript AI projects with Langchain & React

Not sure what to build? Dive in with these Javascript AI projects! Learn how to build LLM powered apps using Langchain.js and React! Connect your apps to LLMs such as OpenAI, create agents, use vector databases, or setup AI context.


Leave a Reply

Your email address will not be published. Required fields are marked *

📘 The Guide to React Home Screencasts Best of Newsletter Search X

📘 - 10 Javascript AI projects with React and LangChain

Hi friend! Before you go, just wanted to let you know about the 10 Javascript AI projects ideas with React and LangChain FREE ebook.

One of the best ways to learn is by doing the work. Choose from these 10 project ideas and start working on topics such as:

  • How does LangChain work
  • Connecting to OpenAI LLM
  • Create AI Agents
  • Simple and Sequential Chains
  • Adding Memory (Chat Context)
  • Prompt Templates
  • Using OutputParsers and Tools for Agents
  • Work with Documents and more...

Keep building and see the new capabilities LLM models can add to your React app! Get all projects as an ebook right to your inbox!

X