Home > Software design >  How to save states between route change in React
How to save states between route change in React

Time:06-05

I have a simple application that shows the list of local hotels. Each list item has a <Link/> that redirects to another component, which displays the location on the map for that specific hotel. When switching routes, it seems that the <ProductList/> component gets destroyed and so do all the states in it. So every time when it makes new API calls and re-renders. I tried to save in local storage on each componentWillUnmount and retrieve it in useEffect() so that I can make API calls conditionally, and it works but sometimes doesn't work.

import React, { useState, useEffect} from "react";
import ProductItem from "../Components/ProductItem";
import axios from "axios";

const ProductList = () => {
  const [hotelList, setHotelList] = useState([]);

  // Get user location by IP
  const getCurrentLocation = () => {
    return fetch("https://ipinfo.io/json?token=MyToken").then(
      (response) => response.json()
    );
  };

  // Get list of hotels in specific location
  const getHotelsInLocation = (destInfo) => {
    console.log('destInfo is: ', destInfo)
    const options = {
      method: "GET",
      url: "https://booking-com.p.rapidapi.com/v1/hotels/search",
      params: {
        checkout_date: "2022-10-01",
        units: "metric",
        dest_id: destInfo.destId,
        dest_type: destInfo.destType,
        locale: "en-gb",
        adults_number: 2,
        order_by: "popularity",
        filter_by_currency: "USD",
        checkin_date: "2022-09-30",
        room_number: 1,
      },
      headers: {
        "X-RapidAPI-Host": "booking-com.p.rapidapi.com",
        "X-RapidAPI-Key": "MyApiKey",
      },
    };
    axios
      .request(options)
      .then(function (response) {
        console.log(response.data.result);
        setHotelList(response.data.result);
      })
      .catch(function (error) {
        console.error(error);
      });
  };

  useEffect(() => {
    getCurrentLocation().then((currentLocation) => {
      console.log("Current city ", currentLocation.city);
      const options = {
        method: "GET",
        url: "https://booking-com.p.rapidapi.com/v1/hotels/locations",
        params: { locale: "en-gb", name: currentLocation.city },
        headers: {
          "X-RapidAPI-Host": "booking-com.p.rapidapi.com",
          "X-RapidAPI-Key":
            "MyApiKey",
        },
      };
      axios
        .request(options)
        .then(function (response) {
          console.log(response.data);
          let destId = response.data[0].dest_id;
          let destType = response.data[0].dest_type;
          const destInfo = { destId, destType };
          getHotelsInLocation(destInfo);
        })
        .catch(function (error) {
          console.error(error);
        });
    });
  }, []);

  return (
    <>
      {hotelList.map((hotel) => (
        <ProductItem key={hotel.hotel_id} hotel={hotel} />
      ))}
    </>
  );
};

export default ProductList;

How could I do so when coming back to <ProductList/> component, it doesn't make new API calls but just display the hotelList from the previous call.

CodePudding user response:

Although caching with useEffect is possible, My recommendation is to consider using one of the query caching libraries such as:

From my experience if you're already using redux toolkit RTK Query will be the fit for you.

CodePudding user response:

The short answer is that

  • You need the list of hotels in a global state instead of local.
  • Use context / redux along with a cache policy in API calls and track your state changes.
  • Skip the API calls based on your application logic and memoize the query result when needed hence in effect memoize the global state.
  • Related