state.js 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import { useEffect, useRef, useState } from "react";
  2. import { isFunction, parse, stringify } from "lib/utils";
  3. const hasWindow = () => {
  4. return typeof window !== "undefined" ? true : false;
  5. };
  6. const hasLocalStorage = () => {
  7. return hasWindow() && window.localStorage ? true : false;
  8. };
  9. const getItem = (key) => {
  10. return hasLocalStorage() ? window.localStorage.getItem(key) : null;
  11. };
  12. const setItem = (key, value) => {
  13. return hasLocalStorage() ? window.localStorage.setItem(key, value) : false;
  14. };
  15. const removeItem = (key) => {
  16. return hasLocalStorage() ? window.localStorage.removeItem(key) : false;
  17. };
  18. // use local storage to store state values for persistent values
  19. export function useLocalStorage(key, initialValue) {
  20. const [storedValue, setStoredValue] = useState(() => {
  21. try {
  22. const item = getItem(key);
  23. return item ? parse(item) : initialValue;
  24. } catch (err) {
  25. log.error("useLocalStorage useState error", err.message || err);
  26. return initialValue;
  27. }
  28. });
  29. const setValue = (value) => {
  30. try {
  31. const item = isFunction(value) ? value(storedValue) : value;
  32. setStoredValue(item);
  33. setItem(key, stringify(item));
  34. } catch (err) {
  35. log.error("useLocalStorage setValue error", err.message || err);
  36. }
  37. };
  38. return [storedValue, setValue];
  39. }
  40. export function useStateCallback(initialState) {
  41. const [state, setState] = useState(initialState);
  42. const cbRef = useRef(null); // mutable ref to store current callback
  43. const setStateCallback = (state, cb) => {
  44. cbRef.current = cb; // store passed callback to ref
  45. setState(state);
  46. };
  47. useEffect(() => {
  48. // cb.current is `null` on initial render, so we only execute cb on state *updates*
  49. if (cbRef.current) {
  50. cbRef.current(state);
  51. cbRef.current = null; // reset callback after execution
  52. }
  53. }, [state]);
  54. return [state, setStateCallback];
  55. }