Fix SSR hydration mismatch for dates
Created ClientDate component that renders dates client-only via useEffect to prevent server/client locale mismatches. Server renders with de-DE as default, client updates to user's locale. Applied to route detail (version dates) and route list (updated dates). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
14b179bb0c
commit
545469eae0
3 changed files with 19 additions and 2 deletions
15
apps/journal/app/components/ClientDate.tsx
Normal file
15
apps/journal/app/components/ClientDate.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { useState, useEffect } from "react";
|
||||
|
||||
/**
|
||||
* Renders a date only on the client to avoid SSR hydration mismatches.
|
||||
* Server renders empty, client fills in with user's locale.
|
||||
*/
|
||||
export function ClientDate({ iso }: { iso: string }) {
|
||||
const [formatted, setFormatted] = useState(new Date(iso).toLocaleDateString("en-US"));
|
||||
|
||||
useEffect(() => {
|
||||
setFormatted(new Date(iso).toLocaleDateString());
|
||||
}, [iso]);
|
||||
|
||||
return <time dateTime={iso}>{formatted}</time>;
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ import { data, redirect } from "react-router";
|
|||
import type { Route } from "./+types/routes.$id";
|
||||
import { getSessionUser } from "~/lib/auth.server";
|
||||
import { getRouteWithVersions, deleteRoute, updateRoute } from "~/lib/routes.server";
|
||||
import { ClientDate } from "~/components/ClientDate";
|
||||
|
||||
|
||||
export async function loader({ params, request }: Route.LoaderArgs) {
|
||||
|
|
@ -156,7 +157,7 @@ export default function RouteDetailPage({ loaderData }: Route.ComponentProps) {
|
|||
<div className="flex items-center justify-between">
|
||||
<span className="font-medium text-gray-700">v{v.version}</span>
|
||||
<span className="text-sm text-gray-500">
|
||||
{new Date(v.createdAt).toLocaleDateString()}
|
||||
<ClientDate iso={v.createdAt} />
|
||||
</span>
|
||||
</div>
|
||||
{v.changeDescription && (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { data, redirect } from "react-router";
|
|||
import type { Route } from "./+types/routes._index";
|
||||
import { getSessionUser } from "~/lib/auth.server";
|
||||
import { listRoutes } from "~/lib/routes.server";
|
||||
import { ClientDate } from "~/components/ClientDate";
|
||||
|
||||
export async function loader({ request }: Route.LoaderArgs) {
|
||||
const user = await getSessionUser(request);
|
||||
|
|
@ -53,7 +54,7 @@ export default function RoutesListPage({ loaderData }: Route.ComponentProps) {
|
|||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-lg font-medium text-gray-900">{route.name}</h2>
|
||||
<span className="text-sm text-gray-500">
|
||||
{new Date(route.updatedAt).toLocaleDateString()}
|
||||
<ClientDate iso={route.updatedAt} />
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-1 flex gap-4 text-sm text-gray-500">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue