Custom Hook for Caching with useState and useEffect

Create a custom React hook that uses useState and useEffect to cache and fetch data, leveraging browser memory.
import { useState, useEffect } from 'react';

const useCachedData = (key, fetchData) => {
  const [data, setData] = useState(() => {
    // Try to get the data from localStorage
    const cachedData = localStorage.getItem(key);
    return cachedData ? JSON.parse(cachedData) : null;

  useEffect(() => {
    // Fetch the data only if it wasn't found in the cache
    if (data === null) {
      fetchData().then(fetchedData => {
        localStorage.setItem(key, JSON.stringify(fetchedData));
  }, [key, data, fetchData]);

  return data;

export default useCachedData;
The `useCachedData` hook takes a key to identify the cache and a fetchData function that returns a promise when called. It initially checks if the data is in localStorage and sets it to state if available. If not, useEffect triggers the fetchData function and caches the new data received asynchronously.
import React from 'react';
import useCachedData from './useCachedData'; // Assuming the hook is exported in a file named useCachedData.js

const ComponentUsingCache = () => {
  // Example fetch function to get data, e.g., from a server
  const fetchData = async () => {
    const response = await fetch('');
    return response.json();

  // Use the custom hook to get and cache the data
  const data = useCachedData('uniqueCacheKey', fetchData);

  if (!data) return <div>Loading...</div>;

  // Render the fetched data
  return (
      <pre>{JSON.stringify(data, null, 2)}</pre>
This React component example utilizes the `useCachedData` hook defined earlier to cache and display data from an API. It passes a unique key and a fetch function to the hook and renders the result. The component shows a loading indicator until the data is fetched.