Sterlin V
Sterlin V

Reputation: 764

React Query with server side rendering using Next.js

I am trying to use react-query with nextjs to prefetch query on server. It works for the initial query which gets a list of items. However when I try to fetch each item inside component it only fetches it on the client side.

export default function Home() {
  const { data } = useQuery("pokemons", fetchPokemons);
  return (
    <>
      <div>
        {data.map((pokemon) => (
          <Pokemon key={pokemon.name} pokemon={pokemon}/>
        ))}
      </div>
    </>
  );
}

export async function getStaticProps() {
  const queryClient = new QueryClient()
  await queryClient.prefetchQuery('pokemons', fetchPokemons)
  const fetchedPokemons = queryClient.getQueryData()
  //query each pokemon
  fetchedPokemons.forEach(async (pokemon) => {
    await queryClient.prefetchQuery(pokemon.name, () => fetchPokemon(pokemon.url))
  });

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
  }
}

And here is code for the component which also queries each item.

const Pokemon = ({pokemon}) => {
  
  const {data} = useQuery(pokemon.name, () => fetchPokemon(pokemon.url))
  // logs only in browser, on server it is undefined
  {console.log(data)}
  return (
    <div>
      <h3>
        Name - {data.name}
        </h3>
        <h4>Base XP - {data.base_experience}</h4>
    </div>
  )
}

Can you please tell me what am I doing wrong that the query doesn't execute on server or is it an issue of the library itself?

Upvotes: 2

Views: 11903

Answers (2)

TkDodo
TkDodo

Reputation: 29028

when you use getQueryData to get data from the cache, you need to provide the key of the data you want to get:

await queryClient.prefetchQuery('pokemons', fetchPokemons)
const fetchedPokemons = queryClient.getQueryData('pokemons')

alternatively, you can use fetchQuery to also retrieve the data immediately

try {
  const fetchedPokemons = await queryClient.fetchQuery('pokemons')
} catch (error) {
  // handle error
}

Be aware that fetchQuery throws errors (as opposed to prefetchQuery, which does not), so you might want to handle errors somehow.

Upvotes: 3

Sterlin V
Sterlin V

Reputation: 764

I was able to solve this by combining two of my fetching functions into one like so

const fetchPokemons = async () => {
  const { data } = await axios.get(
    "https://pokeapi.co/api/v2/pokemon?limit=10&offset=0"
  );

  const pokemonArray = await Promise.all(
    data.results.map(async (pokemon) => {
      const res = await axios.get(pokemon.url);
      return res.data;
    })
  );

  return pokemonArray;
};

export default function Home() {
  const { data } = useQuery("pokemons", fetchPokemons);
  return (
    <>
      <div>
        {data.map((pokemon) => (
          <Pokemon key={pokemon.name} pokemon={pokemon}/>
        ))}
      </div>
    </>
  );
}

export async function getStaticProps() {
  const queryClient = new QueryClient();
  await queryClient.prefetchQuery("pokemons", fetchPokemons);

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
  };
}

Upvotes: 0

Related Questions