Bring back auto-updating relative time
This time, more optimized re-render
This commit is contained in:
parent
a7cc0785f9
commit
5e56ba9fb9
|
@ -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}>
|
||||
|
|
Loading…
Reference in a new issue