'Next.js Dynamic Page using useSWR

I want to create dynamic pages based on the ID of a Saloon profile using useSWR and useRouter, but the data loads in after the pages are rendered.

This is my code:

import useSWR from "swr";
import { useRouter } from "next/router";

const fetcher = (url) => fetch(url).then((res) => res.json());

export default function FindSaloonProfile() {
  const router = useRouter();
  const { id } = router.query;
  const { data, error } = useSWR(
    id ? `/api/getSaloons` : null,
    id ? fetcher : null
  );

  if (error) return <div>failed to load</div>;
  if (!data) return <div>loading...</div>;

  return <>Hello {data.name} </>;
}

If I console.log(data), it starts getting undefined and loads in the data afterward, but then it is too late, as the page is already rendered.

console

What do I do wrong?



Solution 1:[1]

Wrap the fetcher in a function:

const fetcher = (url) =>
  fetch(url).then(
    async (res)=> {
      const result = await res.json();

      if (res.status !== 200) {
        return Promise.reject(result);
      } else {
        return result;
      }
    }
  );

Solution 2:[2]

Next.js is the server-side rendering framework, but mostly SWR works on the client-side merely, so it means API won't fetch data till the page loaded (or Javascript loaded).

Recently, SWR has published a new document for Next.js integration. You can check it out here.

https://swr.vercel.app/docs/with-nextjs

Let me try to keep it in a short explanation

getStaticProps will help you to get data on the server-side

 export async function getStaticProps() {
  // `getStaticProps` is executed on the server side.
  const saloons = await getSaloons() //you can call `fetcher` here too
  return {
    props: {
      fallback: {
        '/api/getSaloons': saloons
      }
    }
  }
}

After that, you need to import SWRConfig for fallback which is for the fetched data (React-Next.js hydration with help you to link your data with React's context)

export default function Page({ fallback }) {
  // SWR hooks inside the `SWRConfig` boundary will use those values.
  return (
    <SWRConfig value={{ fallback }}>
      <FindSaloonProfile />
    </SWRConfig>
  )
}

Lastly, you just have your usual component

import useSWR from "swr";
import { useRouter } from "next/router";

const fetcher = (url) => fetch(url).then((res) => res.json());

export default function FindSaloonProfile() {
  const router = useRouter();
  const { id } = router.query;
  //your data will get from the server initially, and then it will try to fetch again for the update
  const { data, error } = useSWR(
    id ? `/api/getSaloons` : null,
    id ? fetcher : null
  );

  if (error) return <div>failed to load</div>;
  if (!data) return <div>loading...</div>;

  return <>Hello {data.name} </>;
}

Hopefully, my answer is able to help you

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Yilmaz
Solution 2 Nick Vu