I am using an Urql client to make a query to my graphql server. My query looks like this:

const username = () => {
  const { t: translation } = useTranslation(["common", "profile"]);

  const { query, locale } = useRouter();
  const username = query.username;
  const [{ data: userProfileData }] = useUserProfileQuery({
    variables: {
      username: username as string,
    },
    pause: isServer || !username,
  });
  const userProfile = userProfileData?.userProfile;

  return (
    <Text>{userProfile.name}</Text>
  );
};

export default withUrqlClient(createUrqlClient, { ssr: false })(username);

This would be fine, but because I am using the next-i18next library to localise my website, I have to add the getServerSideProps function.

export const getServerSideProps = async ({ locale, locales}: any) => {
  return {
    props: {
      ...(await serverSideTranslations(
        locale,
        ["common", "profile", "settings"],
        null,
        locales
      )),
    },
  };
};

This all works fine, but it means I can't server-side render my page by setting ssr to true like the following:

export default withUrqlClient(createUrqlClient, { ssr: false })(username);

My goal is to make the query on the useUserProfileQuery server.

I read the following guide: https://formidable.com/open-source/urql/docs/advanced/server-side-rendering/#ssr-with-getstaticprops-or-getserversideprops. Which suggested that I do the query in getServerSideProps. As a result, the new getServerSideProps function looks like this:

export const getServerSideProps = async ({ locale, locales, query }: any) => {
  const ssrCache = ssrExchange({ isClient: false });
  const client = initUrqlClient(createUrqlClient(ssrCache), false);
  if (client)
    await client
      .query(UserProfileDocument, {
        username: query.username,
      })
      .toPromise();

  return {
    props: {
      ...(await serverSideTranslations(
        locale,
        ["common", "profile", "settings"],
        null,
        locales
      )),
      urqlState: ssrCache.extractData(),
    },
  };
};

But, I get the following error:

Error: Hydration failed because the initial UI does not match what was rendered on the server.

Warning: Expected server HTML to contain a matching <div> in <div>.

See more info here: https://nextjs.org/docs/messages/react-hydration-error

What am I doing wrong? Please help.

1

There are 1 best solutions below

0
jmecs On BEST ANSWER

The solution is to return userProfile in getServerProps and remove the query from the username function.

Here's what the new getServerProps looks like

export const getServerSideProps: GetServerSideProps = async ({
  locale,
  locales,
  query,
}: any) => {
  const ssrCache = ssrExchange({ isClient: false });
  const client = initUrqlClient(createUrqlClient(ssrCache), false);
  let userProfile = null;
  if (client)
    userProfile = await client
      .query(UserProfileDocument, {
        username: query.username,
      })
      .toPromise();

  return {
    props: {
      ...(await serverSideTranslations(
        locale,
        ["common", "profile", "settings"],
        null,
        locales
      )),
      userProfile: JSON.parse(JSON.stringify(userProfile?.data?.userProfile)),
    },
  };
};

This is what the new username function looks like

const username = ({locale, userProfile}: any) => {
  const { t: translation } = useTranslation(["common", "profile"]);

  return (
    <Text>{userProfile.name}</Text>
  );
};
export default withUrqlClient(createUrqlClient, { ssr: false })(username);