4

I'm working on a project with pokeapi graphql and I made a infinite scroll component that loads more pokemon when you scroll the page. I wanted to have the first 48 pokemons pre loaded with static generation.

So I have my index page the following code:


const Home = ({ fallback }): JSX.Element => {
  return (
    <div>
      <SWRConfig value={fallback}>
        <PokemonList />
      </SWRConfig>
    </div>
  );
};


export const getStaticProps: GetStaticProps = async () => {
  const url =
    'species: pokemon_v2_pokemonspecies(order_by: {id: asc}, limit: 24, offset: 0)';
  const pokemonList = await getPokemonListData({
    url,
  });

  return {
    props: {
      fallback: {
        'species: pokemon_v2_pokemonspecies(order_by: {id: asc}, limit: 24, offset: 0)':
          pokemonList,
      },
    },
    revalidate: 60 * 60 * 24, // 24 hours
  };
};

And I use this custom hook for the data:

import getPokemonListData from '@requests/getPokemonListData';
import useSWRInfinite from 'swr/infinite';

interface IUsePokemonListParams {
  limit?: number;
}

interface IUsePokemonListReponse {
  pokemonList: IBasicPokemonInfo[][];
  isLoading: boolean;
  size: number;
  setSize: (
    size: number | ((_size: number) => number),
  ) => Promise<IBasicPokemonInfo[][]>;
}

export default function usePokemonList({
  limit,
}: IUsePokemonListParams): IUsePokemonListReponse {
  const getKey = (pageIndex, previousPageData) => {
    if (previousPageData && !previousPageData.length) return null; // reached the end
    return `species: pokemon_v2_pokemonspecies(order_by: {id: asc}, limit: ${limit}, offset: ${
      pageIndex * limit
    })`;
  };

  const { data, error, size, setSize } = useSWRInfinite(getKey, url =>
    getPokemonListData({ url }),
  );

  return {
    pokemonList: data,
    isLoading: !error && !data,
    size,
    setSize,
  };
}

on my list component I use the custom hook and list the data in another component:

const PokemonList = (): JSX.Element => {
  const loader = useRef(null);
  const { pokemonList, setSize } = usePokemonList({ limit: 24 });

  useController({ loader, setSize }); // this is my infinite scroll logic, I set the size when I reach the page limit

  useEffect(() => {
    document.body.className = 'initial';
  }, []);

  return (
    <>
      <ol className={styles.cardContainer}>
        <>
          {pokemonList.map((list, index) => (
            <Fragment key={index}>
              {list.map(pokemon => (
                <li key={pokemon.id}>
                  <Pokemon
                    id={pokemon.id}
                    name={pokemon.name}
                    types={pokemon.types}
                    image={pokemon.image}
                  />
                </li>
              ))}
            </Fragment>
          ))}
        </>
      </ol>
      <div ref={loader} />
    </>
  );
};

However, when I call the custom hook on my list component, for some reason the data returned from the hook, in this case the "pokemonList", is undefined and the request has to be made again. Is there something that I'm missing?

Sku
  • 163
  • 2
  • 14
  • It's most likely related to the dynamic key generated by `getKey` in the `useSWRInfinite` call. What is the value returned by `getKey` on first render? – juliomalves Sep 04 '22 at 22:40
  • species: pokemon_v2_pokemonspecies(order_by: {id: asc}, limit: 24, offset: 0), the key seems to be same, even if I copy from the console log it matches the fallback – Sku Sep 05 '22 at 17:52

1 Answers1

1

You have a mistake in your SWRConfig. Instead of <SWRConfig value={fallback}> you should have <SWRConfig value={{fallback}}>

FINDarkside
  • 2,102
  • 1
  • 18
  • 26
  • 1
    You are right, there was a mistake on the SWRConfig. However, after fixing it, the error still persists. The difference is that if I change the useSWRInfinite to useSWR, with a static key the fall back now works (It didnt wok before), so I think it may be something related with the dinamyc key now, but still no lucky – Sku Sep 03 '22 at 22:08