Introduction
Fetching data from APIs is a common task in React applications, which involves handling asynchronous operations. This can become difficult, particularly when dealing with multiple components that require access to the fetched data. To make this process simpler, React provides two powerful features: custom hooks and context.
Custom hooks are a powerful feature in React that allow developers to encapsulate reusable logic and data fetching logic into functions that can be easily accessed from different parts of their application without having to repeat the same code. This makes it possible to create complex applications with ease and efficiency.
Context API is another valuable feature in React that enables you to share data between components in a hierarchical manner. This means that data can be accessed by multiple components without having to pass it down through props, which can be time-consuming and error-prone.
Combining custom hooks with Context API is an excellent way to fetch data from an API and share it across multiple components. This approach makes it easy to manage and reuse data fetching logic while ensuring that the data is available to all the components that need it. In this article, we will explore how to use a custom hook and context together to fetch data from an API and make it available across multiple components.
Code Overview
import React, { createContext, useEffect, useState } from 'react';
const GetData = createContext();
export const useGetData = (url) => {
// State to store the data received from the authenticated link
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
// Fetch data from the authenticated link
useEffect(() => {
const fetchData = async () => {
console.log('Fetching data...');
try {
// Make the authenticated API call here using fetch
// taking care of promises with async/await
const response = await fetch(url, { });
// Check if the response is ok
if (response.ok) {
// Use await to parse the response as JSON
const responseData = await response.json();
console.log('Response data:', responseData);
// Set the data to the state
setData(responseData);
} else {
// Throw an error if the response is not ok
throw new Error(`Something went wrong: ${response.statusText}`);
}
} catch (error) {
// Catch and set the error to the state
setError(error);
console.error('Error fetching data:', error);
} finally {
// Set the loading to false
setLoading(false);
}
};
// Call the async fetchData function
fetchData();
}, [url]);
// Return the data and a provider component to share the data using the Context API
return {
data, loading, error,
GetDataProvider: ({ children }) => (
<GetData.Provider value={data}>
{children}
</GetData.Provider>
),
};
};
export default GetData;
import './App.css';
import { API_URL } from './hooks/config';
import { useGetData } from './hooks/useGetData';
import ShowData from './components/ShowData';
function App() {
const { data, loading, error, GetDataProvider } = useGetData(API_URL);
// Render the data, loading, or error based on the state
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
if (data) {
return (
<GetDataProvider>
<ShowData />
</GetDataProvider>
)
}
};
export default App;
The provided code demonstrates how to fetch data from an API and share it across multiple components using a custom hook and context. It defines a custom hook named useGetData
that encapsulates the data fetching logic and exposes the fetched data, loading status, and error state. The useGetData
hook utilizes the createContext
function to create a context named GetData
, which provides a provider component for sharing data between components. The App
component consumes the useGetData
hook to fetch data from the API and render the data, loading state, or error message based on the current state. Finally, the ShowData
component consumes the shared data from the context to display the fetched data.
Fetching Data with Async/Await
The useGetData
custom hook is designed to fetch data from an API using the fetch API and async/await syntax, which is useful for handling asynchronous operations. The fetchData
function makes an HTTP request and checks the response status. If the response is successful, it parses the JSON data and sets the data state accordingly. If there’s an error, it sets the error state instead.
To prevent unnecessary API calls when the url
prop changes, the fetchData
function is called within the useEffect
hook. This ensures that the function is only called when it needs to be, rather than being called every time the component re-renders.
Behind the scenes, the fetchData
function within the useGetData
hook uses the popular fetch API to make an asynchronous HTTP request. This function is designed to handle any potential errors gracefully, ensuring that the response status is checked before processing the data. If the response is successful, the function will parse the JSON data and set the data state accordingly.
To enhance the performance of the application, the fetchData
function is executed using the useEffect
hook. This ensures that the function is only called when a change in the URL is detected, thereby avoiding unnecessary API calls. With the help of the useGetData
hook, developers can conveniently and reliably fetch data from an API in a safe and efficient manner.
Custom Hooks in React
Custom hooks are a type of function in React that enable you to reuse logic and data fetching across numerous components in your application. Custom hooks help you to separate concerns and make your code more readable and easier to maintain. They allow you to encapsulate specific behavior and make it available to other components without the need to pass props down through the component tree.
For example, let’s consider the useGetData
custom hook. This hook encapsulates the logic for fetching data from an API, managing the loading state, and handling errors. This hook exposes the states and a GetDataProvider
component, which wraps the child components and provides access to the data fetched. This approach makes it easier to fetch data from APIs and reuse the code across various components.
Using the Custom Hook
The App
component utilizes the useGetData
custom hook to fetch data from the API and display it conditionally based on the loading, error, and data states. If the data is available, it renders the ShowData
component, which consumes the data.
Creating Context and Using It
To create a GetData
context, we use the createContext
function. This function defines a context type and a provider component. The provider component acts as a container for the shared data and is responsible for updating the context whenever the data changes.
To consume the GetData
context, the App component uses the GetDataProvider
component. This component wraps the ShowData
component and provides access to the fetched data. This ensures that the ShowData
component can access the data without explicitly passing it down through props.
Benefits of Context API
Using context provides several benefits for sharing data between components:
- Centralized data handling: Context simplifies data management by centralizing it in a single place, eliminating the need to pass data down through props manually.
- Improved data consistency: Context ensures that all components have access to the latest data, eliminating the risk of stale data when using props.
- Reusable data access: Components can easily access the shared data without modifying other components.
Conclusion
By combining custom hooks and context, you can simplify data fetching and sharing in React applications. Custom hooks encapsulate reusable logic and data fetching operations, while context provides a centralized way to share data between components and improve performance. This combination allows you to write cleaner, more maintainable code and better manage data flow in your React applications.
The code is available on GitHub: https://github.com/rezabs/custom-hook-context-fetch-api-reactjs