import { useEffect, useRef, useState } from "react"; import { isFunction, parse, stringify } from "lib/utils"; const hasWindow = () => { return typeof window !== "undefined" ? true : false; }; const hasLocalStorage = () => { return hasWindow() && window.localStorage ? true : false; }; const getItem = (key) => { return hasLocalStorage() ? window.localStorage.getItem(key) : null; }; const setItem = (key, value) => { return hasLocalStorage() ? window.localStorage.setItem(key, value) : false; }; const removeItem = (key) => { return hasLocalStorage() ? window.localStorage.removeItem(key) : false; }; // use local storage to store state values for persistent values export function useLocalStorage(key, initialValue) { const [storedValue, setStoredValue] = useState(() => { try { const item = getItem(key); return item ? parse(item) : initialValue; } catch (err) { log.error("useLocalStorage useState error", err.message || err); return initialValue; } }); const setValue = (value) => { try { const item = isFunction(value) ? value(storedValue) : value; setStoredValue(item); setItem(key, stringify(item)); } catch (err) { log.error("useLocalStorage setValue error", err.message || err); } }; return [storedValue, setValue]; } export function useStateCallback(initialState) { const [state, setState] = useState(initialState); const cbRef = useRef(null); // mutable ref to store current callback const setStateCallback = (state, cb) => { cbRef.current = cb; // store passed callback to ref setState(state); }; useEffect(() => { // cb.current is `null` on initial render, so we only execute cb on state *updates* if (cbRef.current) { cbRef.current(state); cbRef.current = null; // reset callback after execution } }, [state]); return [state, setStateCallback]; }