DEV Community

Francisldn
Francisldn

Posted on

4 2

React Data Fetching Patterns - Part II

This article is a continuation of:

React Data Fetching Patterns - useState-useEffect

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

Custom Hook using React Context API

To deal with the problem of prop-drilling, we could create a custom hook which utilises React Context API. The useState-useEffect data fetching logic can then reside within this hook.

Using the example below, the UserContext component will create the users state, while UserProvider stores the states and provides them to other components through useContext hook.

interface UserProps {
    users: User[],
    loading: boolean,
    error: boolean,
}

export const UserContext = createContext<UserProps>({
    users: [],
    loading: false,
    error: false
})

export const UserProvider = ({children}: {children: React.ReactNode}) => {
    const [users, setUsers] = useState<User[]>([])
    const [error, setError] = useState(false)
    const [loading, setLoading] = useState(false)

    useEffect(() => {
        setLoading(true)
        getUsers(apiURL)
            .then(({results:data}) => {
                console.log({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))
    },[])

    // useMemo hook is used to `memoize` the value so that they only recompute when states have changed
    const value = useMemo(() => ({
        users,
        loading,
        error
    }),[users, loading, error])

    return (
        <UserContext.Provider value={value}>
          {children}
        </UserContext.Provider>
      )
}
// Provide access to other components through useUsers custom hook
export function useUsers() {
    return useContext(UserContext)
}
Enter fullscreen mode Exit fullscreen mode

To provide access of the states to all the child components, we need to wrap the UserProvider around the top level component (<App/>).

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <UserProvider>
      <App />
    </UserProvider>
  </React.StrictMode>
);
Enter fullscreen mode Exit fullscreen mode

For a React component to access the states from UserProvider, the custom hook can be imported, and the required data can be retrieved through the custom hook, as illustrated below. This will allow any React component to have access to a full or subset of the states without having to prop-drill.

import { useUsers } from '../hooks/useUsers';

export default function CardList() {
    const {users, loading, error} = useUsers()

  return (
    <div className="grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 justify-center grid-cols-1 mt-8">
        {loading 
            ? <Loading />
            : error 
            ? <ErrorFallBack />
            : users.map((user:User) => (<CardItem key={`${user.id}${user.email}`} user={user}/>))
        }
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Pros

  • Easy to setup: With the Context API, it is relatively easy to set up and use
  • Easy to understand: The simple setup means that the code is also easily understandable

Cons

  • Unnecessary re-rendering: React will re-render all components whenever there is an update to the value of the props. For a larger app with thousands of components, this will slow down the performance of the app.

To deal with the issue of unnecessary component re-rendering and improve the performance of the app, let's proceed to look at the next data fetching method - Redux.

To be continued:

For more info on React Context, see here.

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

API Trace View

How I Cut 22.3 Seconds Off an API Call with Sentry

Struggling with slow API calls? Dan Mindru walks through how he used Sentry's new Trace View feature to shave off 22.3 seconds from an API call.

Get a practical walkthrough of how to identify bottlenecks, split tasks into multiple parallel tasks, identify slow AI model calls, and more.

Read more →

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay