I am making a Pokemon team builder, and am trying to use react-query as I am trying to use the cache features to not make so many requests to the open and public PokeAPI.
I have a dropdown that allows a user to select the name of a Pokemon. When a Pokemon is selected, I want the 'Moves' dropdown to populate with a list of that Pokemons moves for selection.
My initial approach was to use a useEffect hook that depended on the Pokemon Dex Number.
useEffect(() => {
if (pokeDexNum) {
// fetch `https://pokeapi.co/api/v2/pokemon/${pokeDexNum}`
}
}, [pokeDexNum])
I have no clue however how to use this with React-Query. What I want to do is when a user selects a Pokemon, a fetch is made to the PokeAPI to fetch that pokemons available moves, and puts them into the options
of the 'Moves' dropdown so that they can select moves.
From the code below you can see that when a Pokemon from the 'Pokemon' dropdown is selected, it updates the const [pokeDexNum, setPokeDexNum] = useState(null);
state
<Form>
<Form.Group>
<Form.Dropdown
label="Pokemon"
search
selection
clearable
selectOnBlur={false}
value={pokeDexNum}
onChange={(e, data) => setPokeDexNum(data.value)}
options={[
{ text: "Tepig", value: 498 },
{ text: "Oshawott", value: 501 },
{ text: "Snivy", value: 495 },
]}
/>
<Form.Dropdown label="Moves" search selection options={[]} />
</Form.Group>
</Form>
How would I be able to use react query to fetch depending on whether pokeDexNum
is updated
Example of query
const { isLoading, error, data } = useQuery('getPokeMoves', () =>
fetch(`https://pokeapi.co/api/v2/pokemon/${pokeDexNum}`).then(res =>
res.json()
)
)
The above query sometimes fetches even when pokeDexNum
is null
.
CodePudding user response:
Solution: You need to add your pokeDexNum
to the queryKey
of useQuery.
Here is my suggestion,
define a function to call useQuery
. adding your pokeDexNum
to the queryKey
.
const useGetPokeMoves = (pokeDexNum) => {
return useQuery(
["getPokeMoves", pokeDexNum],
() => {
return fetch(`https://pokeapi.co/api/v2/pokemon/${pokeDexNum}`).then(
(res) => res.json()
);
},
{ keepPreviousData: true }
);
};
Then use it in your component,
const { data } = useGetPokeMoves(pokeDexNum);
Whenever your state changes, the queryKey
will also change and the query will be fetched.
CodePudding user response:
As stated in @Arjun's answer, you need to add the pokeDexNum
state to the queryKey
array. Think of it as a useEffect
's dependency. Any time the pokeDexNum
gets updated/changes, a refetch will be triggered for that query.
Since pokeDexNum
's initial value is null
, you don't want the query to fire before the state is updated. To avoid this, you can use the enabled
option in useQuery
:
const fetchPokemon = (pokeDexNum) => {
return fetch(`https://pokeapi.co/api/v2/pokemon/${pokeDexNum}`).then((res) =>
res.json()
)
}
const { isLoading, error, data } = useQuery(
['getPokeMoves', pokeDexNum],
() => fetchPokemon(pokeDexNum),
{
enabled: Boolean(pokeDexNum)
}
)
Also, it would be a good idea to add some error handling, I imagine you omitted this for brevity.