Search code examples
javascriptreactjsaxiosreact-context

How to fetch data and store in React Context API?


First time using the Context API so please bear with me.

I have a local JSON file that I'm trying to fetch from and place the response in the Context API so I can use globally around the app.

Upon running the app locally, there's a blank screen and the page doesn't seem to load. The page is in an endless loop so I can't see if it's loading or not.

Codesandbox here.

Any idea what I can change to bring in the data response successfully to the Context API?

apiContext.js:

import React, { useContext, useState, useEffect, createContext } from "react";
import axios from "axios";

const APIContext = createContext();

function APIContextProvider({ children }) {
  // Initialize state
  const [data, setData] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  // Fetch data
  useEffect(() => {
    let url = "../db.json";
    axios
      .get(url)
      .then(function (response) {
        setData(response.data.machines);
        setIsLoading(false);
        console.log(response.data.machines);
      })
      .catch((error) => console.log(error));
  }, []);

  return (
    <APIContextProvider value={{ data }} loading={isLoading}>
      {children}
    </APIContextProvider>
  );
}

export default APIContextProvider;

// Create a hook to use the APIContext, this is a Kent C. Dodds pattern
export function useAPI() {
  const context = useContext(APIContext);
  if (context === undefined) {
    throw new Error("Context must be used within a Provider");
  }
  return context;
}

App.js:

import "./App.css";
import List from "./List";
import APIContextProvider from "./context/apiContext";

function App() {
  return (
    <APIContextProvider>
      <div className="App">
        <List />
      </div>
    </APIContextProvider>
  );
}

export default App;

List.js:

import React from "react";
import { useAPI } from "./context/apiContext";

const FetchData = ({ isLoading }) => {
  // Grab data from useAPI in global context
  const { data } = useAPI();

  return (
    <div>{!isLoading ? <p>{data[0].category}</p> : <p>Loading...</p>}</div>
  );
};

export default FetchData;

Solution

  • Try this.

    // apiContext.js
      return (
        <APIContext.Provider value={{ data, isLoading }}>
          {children}
        </APIContext.Provider>
      );
    
    // List.js
    const FetchData = () => {
      // Grab data from useAPI in global context
      const { data, isLoading } = useAPI();
    
      return (
        <div>{!isLoading ? <p>{data[0].category}</p> : <p>Loading...</p>}</div>
      );
    };