DEV Community

Francisldn
Francisldn

Posted on

React Data Fetching Patterns - Part I

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 - an API made available in React v18 (no longer experimental), as follows:

Click here to access the Github repo for the code examples discussed below.

How data fetching is traditionally done

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>
  )
}
Enter fullscreen mode Exit fullscreen mode

Downsides

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. 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:

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

Top comments (0)