skip to Main Content

I am new to React. Trying to build random project.
I create one home page where I fetched data from API and set it to some state X.
Using react-router, routed to Category page where all categories are present.
Again, routed to particular category.
Here all items are visible of that category.
Till here, everything works fine, but when I am refreshing page on this Items page, suddenly, all data is vanished.
Any idea what could be wrong?

Component tree

App

useEffect(function () {
  async function fetchData() {
    try {
      setIsLoading(true);
      const res = await fetch(`${BASE_URL}/gahlot1999/fake-api/categories`);
      const data = await res.json();
      setData(data);
    } catch {
      alert('Error in loading data');
    } finally {
      setIsLoading(false);
    }
  }
  fetchData();
}, []);

<BrowserRouter>
  <Routes>
    <Route path='/' element={<Home />} />
    <Route
      path='/app'
      element={<AppLayout data={data} isLoading={isLoading} />}
    />
    <Route
      path='app/:name'
      element={<Category data={data} isLoading={isLoading} />}
    />
  </Routes>
</BrowserRouter>

Category

return (
  <div className={styles.container}>
    <SideBar name={name} />
    <ItemList name={name} data={data} isLoading={isLoading} />
  </div>
);

ItemList

function ItemList({ name, data }) {
  const items = data.filter(
    (el) => name.toLowerCase() === el.name.toLowerCase(),
  )[0].items;

  return (
    <ul className={styles.itemList}>
      {items.map((el) => (
        <Item item={el} key={crypto.randomUUID()} />
      ))}
    </ul>
  );
}

Item

function Item({ item }) {
  return (
    <li>
      <p>{item.name}</p>
      <p>{item.description}</p>
      <p>{item.price}</p>
    </li>
  );
}

2

Answers


  1. The data state should be initialized from localStorage while data state updates are persisted to localStorage. When the page is loaded/reloaded, the last state that was persisted is provided as the initial state value. When the state updates a useEffect hook persists the state to localStorage.

    Example:

    const [data, setData] = React.useState(() => {
      // lazy initialize state from localStorage
      return JSON.parse(localStorage.getItem("data")) || [];
    });
    
    // Persist state updates to localStorage.
    useEffect(() => {
      localStorage.setItem("data", JSON.stringify(data));
    }, [data]);
    
    useEffect(() => {
      async function fetchData() {
        try {
          setIsLoading(true);
          const res = await fetch(`${BASE_URL}/gahlot1999/fake-api/categories`);
          const data = await res.json();
          setData(data);
        } catch {
          alert('Error in loading data');
        } finally {
          setIsLoading(false);
        }
      }
    
      if (/* condition to fetch data, e.g. if `data` is empty, etc */) {
        fetchData();
      }
    }, [data]);
    
    ...
    
    Login or Signup to reply.
  2. It looks like the issue is related to the data fetching and how you handle the initial state in your application.

    When you refresh the page on the "Items" page, the data fetched on the home page is lost because the component tree is re-rendered from the top. This means the data state in your App component becomes empty, causing an error when rendering the Category component.

    To resolve this, you need to make sure that the data fetched in the Home component is available even after refreshing the page. One common approach is to use browser local storage or session storage to persist the fetched data across page refreshes.

    Here’s a modified version of your code to handle data fetching and persistence using local storage:

    In the App component, check if the data exists in local storage and use it as the initial state. If not, fetch the data and save it in local storage.

    // App component
    import { useEffect, useState } from 'react';
    
    const App = () => {
      const [data, setData] = useState(() => {
        const storedData = localStorage.getItem('data');
        return storedData ? JSON.parse(storedData) : [];
      });
      const [isLoading, setIsLoading] = useState(false);
    
      useEffect(() => {
        async function fetchData() {
          try {
            setIsLoading(true);
            const res = await fetch(`${BASE_URL}/gahlot1999/fake-api/categories`);
            const data = await res.json();
            setData(data);
            localStorage.setItem('data', JSON.stringify(data)); // Save data to local storage
          } catch {
            alert('Error in loading data');
          } finally {
            setIsLoading(false);
          }
        }
    
        fetchData();
      }, []);
    
      return (
        <BrowserRouter>
          {/* Routes and other components */}
        </BrowserRouter>
      );
    };
    

    By using useState with a function as the initial state, you ensure that the data is fetched only on the first load or when the local storage is empty.

    With this modification, when you refresh the "Items" page or navigate back to it, the data should be available from the local storage, preventing the data loss issue you were facing.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search