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:
- RTK Query
- react-query
- Apollo (if you're using GraphQL)
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.