I'm trying to use the useParams hook to grab a value from the route and use it in an async handler function for my page which also uses useEffect and useState.
I noticed that my page works fine until I reference the value (pageId) that I got from useParams. As soon as you reference placeId within fetchPlaces you start getting this error:
React Hook useEffect has a missing dependency: 'fetchPlace'
I do not understand what's going on--why does it fail as soon as I reference the value set by the useParams hook?
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
function PlaceItem() {
const { placeId } = useParams();
const [place, setPlace] = useState([]);
useEffect(() => {
fetchPlace();
}, []);
async function fetchPlace() {
/*** IF YOU DO NOT REFERENCE placeID IT WORKS ***/
const placeData = await API.graphql({
query: queries.getPlaceDetails,
variables: { id: placeId },
});
setPlace(placeData);
}
return <Cards places={place} columns="1" />;
}
export default PlaceItem;
CodePudding user response:
You can also move fetchPlace
inside the hook, as it's not used anywhere else.
import { useParams } from "react-router-dom";
function PlaceItem() {
const { placeId } = useParams();
const [place, setPlace] = useState([]);
useEffect(() => {
async function fetchPlace() {
const placeData = await API.graphql({
query: queries.getPlaceDetails,
variables: { id: placeId },
});
setPlace(placeData);
}
fetchPlace();
}, [placeId]);
return <Cards places={place} columns="1" />;
}
export default PlaceItem;
CodePudding user response:
You try to hide it but placeId
is a dependency of the effect. You may also consider useCallback
around fetchPlace
.
function PlaceItem() {
const { placeId } = useParams();
const [place, setPlace] = useState([]);
useEffect(() => {
fetchPlace(placeId); // ✅
}, [placeId]); // ✅
async function fetchPlace(placeId) { // ✅
const placeData = await API.graphql({
query: queries.getPlaceDetails,
variables: { id: placeId },
});
setPlace(placeData);
}
return <Cards places={place} columns="1" />;
}
Another answer suggest to write fetchPlace inside the effect but I think this is more sanitary.
function PlaceItem() {
const { placeId } = useParams();
const [place, setPlace] = useState([]);
useEffect(() => {
API.graphql({
query: queries.getPlaceDetails,
variables: { id: placeId },
})
.then(setPlace) // ✅
}, [placeId]);
return <Cards places={place} columns="1" />;
}