UNPKG

@dr.pogodin/react-utils

Version:

Collection of generic ReactJS components and utils

85 lines (83 loc) 2.91 kB
import { serialize } from 'cookie'; import { useEffect } from 'react'; import dayjs from 'dayjs'; import { DAY_MS, HOUR_MS, MIN_MS, SEC_MS, YEAR_MS, timer } from '@dr.pogodin/js-utils'; import { useGlobalState } from '@dr.pogodin/react-global-state'; import { getSsrContext } from "./globalState"; /** * This react hook wraps Date.now() function in a SSR friendly way, * ensuring that all calls to useCurrent() within the same render return * exactly the same time (which is retrieved from Date.now() first, and * then stored in the global state to be reused in all other calls), which * is also passed and used in the first client side render, and then updated * with a finite precision to avoid infinite re-rendering loops. */ // TODO: Should we request the state type as generic parameter, to be able // to verify the give globalStatePath is correct? export function useCurrent({ autorefresh = false, globalStatePath = 'currentTime', precision = 5 * SEC_MS } = {}) { const [now, setter] = useGlobalState(globalStatePath, Date.now); useEffect(() => { let timerId; const update = () => { setter(old => { const neu = Date.now(); return Math.abs(neu - old) > precision ? neu : old; }); if (autorefresh) timerId = setTimeout(update, precision); }; update(); return () => { if (timerId) clearTimeout(timerId); }; }, [autorefresh, precision, setter]); return now; } /** * Wraps the standard Date.getTimezoneOffset() method in a SSR-friendly way. * This hook retrieves the offset value at the client side and uses a cookie * to pass it to the server in subsequent requests from that user. At the server * side the value from cookie is used in renders and passed back to the client * via the global state. Prior to the value being known (in the very first * request from the user, when the cookie is still missing), zero value is used * as the default value. */ // TODO: Should we request the state type as generic parameter, to be able // to verify the give globalStatePath is correct? export function useTimezoneOffset({ cookieName = 'timezoneOffset', globalStatePath = 'timezoneOffset' } = {}) { const ssrContext = getSsrContext(false); const [offset, setOffset] = useGlobalState(globalStatePath, () => { const value = cookieName && ssrContext?.req.cookies[cookieName]; return value ? parseInt(value) : 0; }); useEffect(() => { const date = new Date(); const value = date.getTimezoneOffset(); setOffset(value); if (cookieName) { document.cookie = serialize(cookieName, value.toString(), { path: '/' }); } }, [cookieName, setOffset]); return offset; } const time = { DAY_MS, HOUR_MS, MIN_MS, SEC_MS, YEAR_MS, now: Date.now, timer, useCurrent, useTimezoneOffset }; export default Object.assign(dayjs, time); //# sourceMappingURL=time.js.map