Bring back auto-updating relative time

This time, more optimized re-render
This commit is contained in:
Lim Chee Aun 2024-03-30 17:21:31 +08:00
parent a7cc0785f9
commit 5e56ba9fb9

View file

@ -8,7 +8,7 @@ import dayjs from 'dayjs';
import dayjsTwitter from 'dayjs-twitter';
import localizedFormat from 'dayjs/plugin/localizedFormat';
import relativeTime from 'dayjs/plugin/relativeTime';
import { useMemo } from 'preact/hooks';
import { useEffect, useMemo, useReducer } from 'preact/hooks';
dayjs.extend(dayjsTwitter);
dayjs.extend(localizedFormat);
@ -18,22 +18,49 @@ const dtf = new Intl.DateTimeFormat();
export default function RelativeTime({ datetime, format }) {
if (!datetime) return null;
const [renderCount, rerender] = useReducer((x) => x + 1, 0);
const date = useMemo(() => dayjs(datetime), [datetime]);
const dateStr = useMemo(() => {
const [dateStr, dt, title] = useMemo(() => {
let str;
if (format === 'micro') {
// If date <= 1 day ago or day is within this year
const now = dayjs();
const dayDiff = now.diff(date, 'day');
if (dayDiff <= 1 || now.year() === date.year()) {
return date.twitter();
str = date.twitter();
} else {
return dtf.format(date.toDate());
str = dtf.format(date.toDate());
}
}
return date.fromNow();
}, [date, format]);
const dt = useMemo(() => date.toISOString(), [date]);
const title = useMemo(() => date.format('LLLL'), [date]);
if (!str) str = date.fromNow();
return [str, date.toISOString(), date.format('LLLL')];
}, [date, format, renderCount]);
useEffect(() => {
let timeout;
let raf;
function rafRerender() {
raf = requestAnimationFrame(() => {
rerender();
scheduleRerender();
});
}
function scheduleRerender() {
// If less than 1 minute, rerender every 10s
// If less than 1 hour rerender every 1m
// Else, don't need to rerender
if (date.diff(dayjs(), 'minute', true) < 1) {
timeout = setTimeout(rafRerender, 10_000);
} else if (date.diff(dayjs(), 'hour', true) < 1) {
timeout = setTimeout(rafRerender, 60_000);
}
}
scheduleRerender();
return () => {
clearTimeout(timeout);
cancelAnimationFrame(raf);
};
}, []);
return (
<time datetime={dt} title={title}>