this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Bring back auto-updating relative time

This time, more optimized re-render

+35 -8
+35 -8
src/components/relative-time.jsx
··· 8 8 import dayjsTwitter from 'dayjs-twitter'; 9 9 import localizedFormat from 'dayjs/plugin/localizedFormat'; 10 10 import relativeTime from 'dayjs/plugin/relativeTime'; 11 - import { useMemo } from 'preact/hooks'; 11 + import { useEffect, useMemo, useReducer } from 'preact/hooks'; 12 12 13 13 dayjs.extend(dayjsTwitter); 14 14 dayjs.extend(localizedFormat); ··· 18 18 19 19 export default function RelativeTime({ datetime, format }) { 20 20 if (!datetime) return null; 21 + const [renderCount, rerender] = useReducer((x) => x + 1, 0); 21 22 const date = useMemo(() => dayjs(datetime), [datetime]); 22 - const dateStr = useMemo(() => { 23 + const [dateStr, dt, title] = useMemo(() => { 24 + let str; 23 25 if (format === 'micro') { 24 26 // If date <= 1 day ago or day is within this year 25 27 const now = dayjs(); 26 28 const dayDiff = now.diff(date, 'day'); 27 29 if (dayDiff <= 1 || now.year() === date.year()) { 28 - return date.twitter(); 30 + str = date.twitter(); 29 31 } else { 30 - return dtf.format(date.toDate()); 32 + str = dtf.format(date.toDate()); 33 + } 34 + } 35 + if (!str) str = date.fromNow(); 36 + return [str, date.toISOString(), date.format('LLLL')]; 37 + }, [date, format, renderCount]); 38 + 39 + useEffect(() => { 40 + let timeout; 41 + let raf; 42 + function rafRerender() { 43 + raf = requestAnimationFrame(() => { 44 + rerender(); 45 + scheduleRerender(); 46 + }); 47 + } 48 + function scheduleRerender() { 49 + // If less than 1 minute, rerender every 10s 50 + // If less than 1 hour rerender every 1m 51 + // Else, don't need to rerender 52 + if (date.diff(dayjs(), 'minute', true) < 1) { 53 + timeout = setTimeout(rafRerender, 10_000); 54 + } else if (date.diff(dayjs(), 'hour', true) < 1) { 55 + timeout = setTimeout(rafRerender, 60_000); 31 56 } 32 57 } 33 - return date.fromNow(); 34 - }, [date, format]); 35 - const dt = useMemo(() => date.toISOString(), [date]); 36 - const title = useMemo(() => date.format('LLLL'), [date]); 58 + scheduleRerender(); 59 + return () => { 60 + clearTimeout(timeout); 61 + cancelAnimationFrame(raf); 62 + }; 63 + }, []); 37 64 38 65 return ( 39 66 <time datetime={dt} title={title}>