Search code examples
reactjsreact-hooksfetchrerender

React fetch side effect


My post is more of a question than a problem. In react, in order to fetch data from an API we use the hook useEffect. But why not just work with states to manage the re-renderings ? (see example bellow)

import React from "react"

export default function App() {
    const [starWarsData, setStarWarsData] = React.useState({})
    const [isLoaded, setIsLoaded] = React.useState(false)

    if (!isLoaded) {
        const randomIndex = Math.floor(Math.random()*50)
        fetch(`https://swapi.dev/api/people/${randomIndex}`)
        .then(res => res.json())
        .then(data => setStarWarsData(data))
        setIsLoaded(true)
    }


    return (
        <div>
            <pre>{JSON.stringify(starWarsData, null, 2)}</pre>
            <button onClick={() => setIsLoaded(false)}>Load random charachter</button>
        </div>
    )
}

As you can see, I manage the re-rendering with a simple if statement. Can you tell me why I should go with useEffect when fetching data and not the way presented above ?

Thanks in advance


Solution

  • Well, I actually think it's a great question :)

    Technically, what you are doing here will work, because you are making sure the fetch will occur only once and will not retrigger infinite renders.

    But there are some flaws with performing side effects inside the render phase:

    1. You are using useState inside the render phase, which means that you are in danger of re triggering the render phase infinitely.
    2. Let's assume you would only want to fetch the data once after the mount phase has completed (useEffect with empty dependency array OR componentDidMount event in class components) - You could get rid of the isLoaded state and use only 1 state for storing the data, because the code will trigger only once, and you won't have to worry about re renders with the isLoaded state.
    3. In every single render, you are going to check if isLoaded is false, which is redundant because we know exactly when we want to refetch data. (Only after mount, and after clicking on the 'Load random character' button)

    By using useEffect - you are making sure the data fetching will not interrupt the UI, and will not retrigger renders unwillingly by using an array of dependencies. By using this hook, the code is cleaner, and you know exactly when it will be called.

    (side note - remember that setState is asynchronous, which can lead into unexpected renders, and also to some issues if you rely on the previous value of that state)