Reza Savadkouhi

REACT JS – Simplify Data Fetching in React with Hooks and Context
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
JavaScript
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;
JavaScript
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

Leave a Comment

Your email address will not be published. Required fields are marked *