React Data Fetching Patterns - Part I
Tags: react, swr, redux, reactquery
Published: 2022-11-16 12:09:23

In React, **data fetching** from an external API typically involves a few steps, as below:
1. send a fetch request
2. await for response
3. receive the requested data or error

In this article, we will first discuss how data fetching is traditionally done in React using ``useState-useEffect`` hooks. We will then proceed to discuss other data fetching patterns, utilising [Suspense](https://reactjs.org/blog/2022/03/29/react-v18.html) - an API made available in React v18 (no longer experimental), as follows:

* [Custom hook using Context API](https://dev.to/francisldn/react-data-fetching-patterns-part-ii-10gg)
* [Redux](https://dev.to/francisldn/react-data-fetching-pattern-part-iii-584d)
* [SWR](https://dev.to/francisldn/react-data-fetching-pattern-part-iv-3mbe)
* [React Query](https://dev.to/francisldn/react-data-fetching-pattern-part-v-2oen)

Click [here](https://github.com/francisldn/React-Data-Fetching-Patterns) to access the Github repo for the code examples discussed below.

<h3>How data fetching is traditionally done</h3>
In React, we traditionally perform data fetching using ``useState-useEffect`` hooks. Within a React component, a state is created using ``useState`` hook to store data. ``useEffect`` hook is executed as the component first mounts or page first renders. The data fetching logic in the useEffect hook will run and data will be stored as a state.

Let's go through the code:
* ``users`` state is declared with ``useState``, together with loading and error states
* Within ``useEffect``, ``getUsers`` function will execute on component mounts, and the loading state will set to true while waiting for data to be retrieved
* On successful data retrieval, the loading and error states will set to false, and ``users`` state will contain the retrieved data, ready for UI rendering.
```
export default function CardList() {
    const [users, setUsers] = useState<User[]>([])
    const [isLoading, setLoading] = useState(false)
    const [isError, setError] = useState(false)

    useEffect(() => { 
        setLoading(true)  
        getUsers(apiURL)
            .then(({results:data}) => {
                setUsers(
                data.map((user:UserApi) => {
                    return {
                        id: user.id.value,
                        firstName: user.name.first,
                        lastName: user.name.last,
                        username: user.login.username,
                        email: user.email,
                    }}))
                })
            .catch(() => setError(true))
            .finally(() => setLoading(false))
    },[])

  return (
    <div className="grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 justify-center grid-cols-1 mt-8">
        {isLoading 
        ? <Loading />
        : isError 
        ? <ErrorFallBack />
        : users.map((user:User) => (<CardItem key={user.id} user={user}/>))
        }
    </div>
  )
}
```
<h4>Downsides</h4>
*Prop-drilling*
While this data fetching pattern works fine for a local component, if there were multiple components that require access to the same set or a subset of the data, then we will need to pass the props through multiple child components, which could lead to [problems of prop-drilling](https://kentcdodds.com/blog/prop-drilling). For a larger app, prop-drilling through multiple layers of components can make the app unwieldy and hard to manage. 

To overcome the issues outlined above, let's proceed to look at a few other data fetching methods, as below.

To be continued:
* [Custom hook using Context API](https://dev.to/francisldn/react-data-fetching-patterns-part-ii-10gg)
* [Redux](https://dev.to/francisldn/react-data-fetching-pattern-part-iii-584d)
* [SWR](https://dev.to/francisldn/react-data-fetching-pattern-part-iv-3mbe)
* [React Query](https://dev.to/francisldn/react-data-fetching-pattern-part-v-2oen)


***If you like the content, please hit the like button so that it can reach more people.***