import { SessionStorage } from '@/utils'; import _ from 'lodash'; import { useEffect, useRef, useState } from 'react'; import * as yup from 'yup'; const sessionStorageInstance = new SessionStorage(); type ISetter = (newValue: unknown) => unknown; function buildSetter(key: string, currentValue: unknown, callback: ISetter): ISetter { return function (newValue: unknown) { const updatedValue = _.isFunction(newValue) ? newValue(currentValue) : newValue; sessionStorageInstance.set(key, updatedValue); callback(updatedValue); return updatedValue; }; } /** * React hook for synchronizing a state value with browser SessionStorage. * * This hook provides a stateful value and a setter function, similar to `useState`, * but persists the value in SessionStorage under the specified key across the same session. * * Use this hook only when you need to persist state across tabs within the same session. * If you need to persist state across sessions, consider using `useLocalStorage` * instead. * * Example: * ```tsx * const [value, setValue] = useSessionStorage('myKey', 'defaultValue'); * * // Read the value * console.log(value); * * // Update the value (persists to SessionStorage) * setValue('newValue'); * ``` * * @param key - The SessionStorage key to store the value under. Must be a non-empty string. * @param defaultValue - The default value to use if the key does not exist in SessionStorage. * @returns A tuple containing the current value and a setter function to update it. * */ function useSessionStorage(key: string, defaultValue?: unknown): [unknown, (newValue: unknown) => unknown] { yup.string().required().validateSync(key); const [state, setState] = useState(sessionStorageInstance.get(key) ?? defaultValue); const defaultValueRef = useRef(defaultValue); const storedDefaultValue = _.isEqual(defaultValueRef.current, defaultValue) ? defaultValueRef.current : defaultValue; const setterRef = useRef<{ key: string; value: unknown; setter: ISetter } | undefined>(); const storedSetter = setterRef.current; useEffect(() => { setState(sessionStorageInstance.get(key) ?? storedDefaultValue); }, [key, storedDefaultValue, setState]); useEffect(() => { function listener(value: unknown) { setState(value); } sessionStorageInstance.watch(key, listener); return () => { sessionStorageInstance.unwatch(key, listener); }; }, [key, setState]); if (key !== storedSetter?.key || !_.isEqual(state, storedSetter?.value)) { setterRef.current = { key, value: state, setter: buildSetter(key, state, setState) }; } return [state, setterRef.current?.setter ?? _.noop]; } export { useSessionStorage };