Home > Software design >  Make a query based on a state change
Make a query based on a state change

Time:12-31

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.

  • Related