@dr.pogodin/react-utils
Version:
Collection of generic ReactJS components and utils
85 lines (83 loc) • 2.91 kB
JavaScript
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