typescriptnext.jsprismahydrationgetserversideprops

Next.js Hydration Error: Text content does not match server-rendered HTML. U+202F vs. U+0020


I am working with dates and Next.js. Below are the three errors I am getting:

Warning: Text content did not match. Server: "Tuesday, January 24, 2023 at 11:01 AM" Client: "Tuesday, January 24, 2023 at 11:01 AM"

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

Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.

I believe the last two come naturally after the first one.

As you may have noticed, the texts that did not match the server and client are identical. However, I noticed that the space between "11:01" and "AM" is a narrow no-break space (U+202F) for the server and space (U+0020) for the client.

I am using getServerSideProps as described below:

export async function getServerSideProps() {
  const eventsResult = (await prisma.event.findMany()).slice(0, 3);
  const newsResult = (await prisma.news.findMany()).slice(0, 3);

  return {
    props: {
      events: JSON.parse(JSON.stringify(eventsResult)),
      news: JSON.parse(JSON.stringify(newsResult)),
      backgroundColor: "red",
    },
  };
}

At first, I thought it might have something to do with JSON.parse and JSON.stringify. So, I changed it with no luck:

export async function getServerSideProps() {
  const eventsResult = (await prisma.event.findMany()).slice(0, 3);
  const newsResult = (await prisma.news.findMany()).slice(0, 3);

  const formattedEventsResults = eventsResult.map((e) => ({
    ...e,
    start: e.start.toString(),
    end: e.start.toString(),
  }));

  const formattedNewsResult = newsResult.map((n) => ({
    ...n,
    datetime: n.datetime.toString(),
  }));

  return {
    props: {
      events: formattedEventsResults,
      news: formattedNewsResult,
      backgroundColor: "red",
    },
  };
}

The exact line in the component that displays the date above is:

(I am trying to avoid timezone conversions because all the dates are for a simple project using all fake data. I just need the stored and displayed values to match)

{new Date(props.start).toLocaleString(undefined, {
  timeZone: "UTC",
  year: "numeric",
  month: "long",
  day: "2-digit",
  weekday: "long",
  hour: "2-digit",
  minute: "2-digit",
})}

How can I ensure the server and client render the same character and avoid the hydration errors?


Solution

  • I solved this issue by replacing all spaces in the formatted date with a standard space. e.g.

    const myFormattedDate = new Date().toLocaleString(undefined, {
      timeZone: "UTC",
      year: "numeric",
      month: "long",
      day: "2-digit",
      weekday: "long",
      hour: "2-digit",
      minute: "2-digit",
    }).replace(/\s/g, ' ')