first of all my project link on github: https://github.com/ARN1380/BookingHotel
I'm using react-router dom v6, I have a BookmarkList in my project and I need to add or delete bookmarks from it, the problem is when I add a bookmark from another component I need to navigate to the BookmarkList component. This navigation was supposed to rerender the BookmarkList but it does not so my custom Hook doesn't run and new list doesn't get fetch from server. (if i refresh the page it does fetch and everything is ok) edit: it does rerender here is my BookmarkList component:
import ReactCountryFlag from "react-country-flag";
import { useBookmarks } from "../context/BookmarksProvider";
import { Link } from "react-router-dom";
import { closePopup } from "../map/Map";
import { HiTrash } from "react-icons/hi";
export default function BookmarkList() {
const {bookmarks, deleteBookmark} = useBookmarks();
function handleBookmarkDelete(e, id) {
e.preventDefault();
deleteBookmark(id);
}
return (
<div>
<h2>Bookmark List</h2>
<div className="bookmarkList">
{bookmarks.map((bookmark) => {
return (
<Link
key={bookmark.id}
to={`${bookmark.id}?lat=${bookmark.latitude}&lng=${bookmark.longitude}`}
onClick={closePopup}
>
<div className="bookmarkItem">
<div>
<ReactCountryFlag svg countryCode={bookmark.countryCode} />
<strong>{bookmark.cityName}</strong> {" "}
<span>{bookmark.country}</span>
</div>
<button
type="button"
onClick={(e) => {
handleBookmarkDelete(e, bookmark.id);
}}
>
<HiTrash className="trash" />
</button>
</div>
</Link>
);
})}
</div>
</div>
);
}
and this is AddBookmark component:
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAnglesLeft } from "@fortawesome/free-solid-svg-icons";
import { useNavigate, useSearchParams } from "react-router-dom";
import useFetch from "../../hooks/useFetch";
import { useBookmarks } from "../context/BookmarksProvider";
import { useEffect, useId, useState } from "react";
import {v4 as uuidv4} from 'uuid';
export default function AddBookmarks() {
const navigate = useNavigate();
const [searchParams, setSearchParams] = useSearchParams();
const [cityNameState, setCityNameState] = useState("");
const [countryNameState, setCountryNameState] = useState("");
const {addBookmark} = useBookmarks();
const lat = searchParams.get("lat");
const lng = searchParams.get("lng");
const {isLoading, data} = useFetch(
"https://api.bigdatacloud.net/data/reverse-geocode-client",
`latitude=${lat}&longitude=${lng}`
);
useEffect(() => {
if (data) {
setCityNameState(locationData.city);
setCountryNameState(locationData.countryName);
}
}, [data]);
if (isLoading) return <div>Loading ...</div>;
const locationData = data;
function handleSubmit(e) {
e.preventDefault();
const newBookmark = {
cityName: cityNameState || locationData.locality,
countryName: countryNameState,
countryCode: locationData.countryCode,
latitude: `${locationData.latitude}`,
longitude: `${locationData.longitude}`,
host_location: locationData.city + " " + locationData.countryName,
id: uuidv4(),
};
addBookmark(newBookmark);
navigate("/bookmark");
}
return (
<div className="capitalize">
<h2 className="font-bold">add bookmark</h2>
<form className="mt-2 [&>div>label]:text-sm" onSubmit={handleSubmit}>
<div className="flex flex-col">
<label className="">city:</label>
<input
className="border-b border-0 border-solid mt-2"
type="text"
required
value={cityNameState}
onChange={(e) => setCityName(e.target.value)}
/>
</div>
<div className="flex flex-col mt-4">
<label>country:</label>
<input
className="border-b border-0 border-solid mt-2"
type="text"
required
value={countryNameState}
onChange={(e) => setCountryName(e.target.value)}
/>
</div>
<div className="mt-5 flex justify-between">
<button
onClick={() => {
navigate(-1);
}}
type="button"
className="border border-slate-400 border-solid rounded-md flex space-x-1 items-center p-0.5 px-1"
>
<FontAwesomeIcon icon={faAnglesLeft} size="xs" />
<p>Back</p>
</button>
<button className="bg-purple-600 text-white px-3 py-0.5 rounded-md">
save
</button>
</div>
</form>
</div>
);
}
and this is my useFetch custom hook in case:
import axios, { AxiosError } from "axios";
import { useEffect, useState } from "react";
import { toast } from "react-hot-toast";
export default function useFetch(url, query = "") {
const [data, setData] = useState();
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setIsLoading(true);
axios
.get(`${url}?${query}`)
.then((response) => {
setData(response.data);
})
.catch((err) => {
toast.error(err.message);
})
.finally(() => setIsLoading(false));
}, [url, query]);
return {isLoading, data};
}
here is my routing in App.jsx:
<Routes>
<Route path="/" element={<HotelsList />} />
<Route path="/search" element={<SearchLayout />}>
<Route index element={<Hotels />} />
<Route path="Hotels/:id" element={<SingleHotel />} />
</Route>
<Route path="/bookmark" element={<BookmarkLayout />}>
<Route index element={<BookmarkList />} />
<Route path=":id" element={<SingleBookmark />} />
<Route path="add" element={<AddBookmarks /> } />
</Route>
<Route path="/404" element={<ErrorPage />} />
<Route path="*" element={<Navigate to="/404" />} />
</Routes>
what is my problem? i can't see why BookmarkList doesn't rerender when navigate happens ...
i tried using an useEffect in BookmarkList component but it didn't work
adding path="/bookmark/" to
<Route path="/bookmark/" index element={} />
In your bookmarksProvider you have this code:
In your
addBookmarkfunction, you only POST to the url. I'm assuming you then wantuseFetchto automatically refetch bookmarks. That won't happen because of the useEffect you use inuseFetch. The useFetch will only rerun whenurlorquerychanges. Since those are hardcoded,useEffectwill be run once and never again (unless you refresh your window of course).You will need to create a way to either add the new bookmark to your data array, or add a new parameter to
useFetch, that you can update with a new unique value so that useEffect within useFetch will run again.Another option is to add a function to your context (
getBookmarksfor instance) that you can call withuseEffectinside of your list page so that everytime you visit the list page, the bookmarks are fetched.