useLocalStorage.js 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import React from "react";
  2. import { atomFamily, useRecoilState } from "recoil";
  3. const getFromLocalStorage = (key) => {
  4. const item = window.localStorage.getItem(key);
  5. if (item === null) {
  6. return null;
  7. }
  8. return JSON.parse(item);
  9. };
  10. const localStorageFamily = atomFamily({
  11. key: "localstorage",
  12. default: (key) => [false, getFromLocalStorage(key)],
  13. });
  14. const useLocalStorage = (key, initialValue) => {
  15. const [[loaded, storedValue], setStoredValue] = useRecoilState(
  16. localStorageFamily(key)
  17. );
  18. React.useEffect(() => {
  19. if (!loaded) {
  20. try {
  21. // Get from local storage by key
  22. const item = window.localStorage.getItem(key);
  23. if (item === null) {
  24. // If missing we add it
  25. window.localStorage.setItem(key, JSON.stringify(initialValue));
  26. setStoredValue([true, initialValue]);
  27. }
  28. setStoredValue([true, JSON.parse(item)]);
  29. } catch (error) {
  30. // If error also return initialValue
  31. console.log(error);
  32. setStoredValue([true, initialValue]);
  33. }
  34. }
  35. }, [initialValue, key, loaded, setStoredValue]);
  36. // Return a wrapped version of useState's setter function that ...
  37. // ... persists the new value to localStorage.
  38. const setValue = React.useCallback(
  39. (value) => {
  40. try {
  41. // Save state
  42. setStoredValue(([, prev]) => {
  43. // Allow value to be a function so we have same API as useState
  44. const valueToStore = value instanceof Function ? value(prev) : value;
  45. // Save to local storage
  46. window.localStorage.setItem(key, JSON.stringify(valueToStore));
  47. return [true, valueToStore];
  48. });
  49. } catch (error) {
  50. // A more advanced implementation would handle the error case
  51. console.log(error);
  52. }
  53. },
  54. [key, setStoredValue]
  55. );
  56. // React on other tab modifications
  57. React.useEffect(() => {
  58. const localStorageChanged = (e) => {
  59. if (e.key === key) {
  60. setStoredValue([true, JSON.parse(e.newValue)]);
  61. }
  62. };
  63. window.addEventListener("storage", localStorageChanged);
  64. return () => {
  65. window.removeEventListener("storage", localStorageChanged);
  66. };
  67. }, [key, setStoredValue]);
  68. return [storedValue === null ? initialValue : storedValue, setValue];
  69. };
  70. export default useLocalStorage;