React Data Fetching Patterns - Part II
Tags: react, reactcontext, reacthook, api
Published: 2022-11-16 16:31:05

This article is a continuation of:

[React Data Fetching Patterns - useState-useEffect](https://dev.to/francisldn/react-data-fetching-patterns-40mg)

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

<h3>Custom Hook using React Context API</h3>
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)
}
```
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>
);
```
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>
  )
}
```

<h4>Pros</h4>
* *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

<h4>Cons</h4>
* *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:
* [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)


For more info on React Context, see [here](https://reactjs.org/docs/context.html).

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