Skip to content

Instantly share code, notes, and snippets.

@nitedani
Created May 13, 2024 16:59
Show Gist options
  • Save nitedani/357a9f298eb0b8e4393df706e8868a16 to your computer and use it in GitHub Desktop.
Save nitedani/357a9f298eb0b8e4393df706e8868a16 to your computer and use it in GitHub Desktop.
DateTime component that fixes React SSR and Client rendering mismatch.
import React, { useId, useMemo } from "react";
export const DateTime = (
props: {
date?: Date | null;
format: (date: Date) => string;
placeholder?: string;
} & React.HTMLAttributes<"span">
) => {
const { format, date } = props;
const key = useId();
if (!date) {
return props.placeholder;
}
const id = `__placeholder__${key}`;
const idScript = `__placeholder__${key}__script`;
const allFormattedDates: { [key: string]: string } = {};
const localOffsetHours = -(new Date().getTimezoneOffset() / 60).toFixed(1);
let localFormattedDate: string;
if (import.meta.env.SSR) {
const allOfsetsHours = [
+0.0, +1.0, +2.0, +3.0, +3.5, +4.0, +4.5, +5.0, +5.5, +5.75, +6.0, +6.5,
+7.0, +8.0, +8.75, +9.0, +9.5, +10.0, +10.5, +11.0, +12.0, +12.75, +13.0,
+13.75, +14.0, -1.0, -2.0, -2.5, -3.0, -3.5, -4.0, -4.5, -5.0, -6.0, -7.0,
-8.0, -9.0, -9.5, -10.0, -11.0, -12.0,
];
for (const offsetHours of allOfsetsHours) {
allFormattedDates[offsetHours] = format(
new Date(
date.getTime() + (offsetHours - localOffsetHours) * 60 * 60 * 1000
)
).replaceAll("\u202F", " ");
}
localFormattedDate = allFormattedDates[localOffsetHours];
} else {
// eslint-disable-next-line react-hooks/rules-of-hooks
localFormattedDate = useMemo(() => format(date), [format, date]);
}
return (
<>
<span id={id} className={props.className} style={props.style}>
{localFormattedDate}
</span>
<script
id={idScript}
dangerouslySetInnerHTML={{
__html: import.meta.env.SSR
? `
{
const allFormattedDates = JSON.parse('${JSON.stringify(
allFormattedDates
)}');
const localOffsetHours = -(new Date().getTimezoneOffset() / 60).toFixed(1);
const localFormattedDate = allFormattedDates[localOffsetHours];
document.getElementById('${id}').innerHTML = localFormattedDate;
document.getElementById('${idScript}').innerHTML= '';
}
`
: "",
}}
></script>
</>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment