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 === undefined) {
  6. return undefined;
  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 === undefined) {
  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. // Allow value to be a function so we have same API as useState
  42. const valueToStore =
  43. value instanceof Function ? value(storedValue) : value;
  44. // Save state
  45. setStoredValue([true, valueToStore]);
  46. // Save to local storage
  47. window.localStorage.setItem(key, JSON.stringify(valueToStore));
  48. } catch (error) {
  49. // A more advanced implementation would handle the error case
  50. console.log(error);
  51. }
  52. },
  53. [key, setStoredValue, storedValue]
  54. );
  55. // React on other tab modifications
  56. React.useEffect(() => {
  57. const localStorageChanged = (e) => {
  58. if (e.key === key) {
  59. setStoredValue([true, JSON.parse(e.newValue)]);
  60. }
  61. };
  62. window.addEventListener("storage", localStorageChanged);
  63. return () => {
  64. window.removeEventListener("storage", localStorageChanged);
  65. };
  66. }, [key, setStoredValue]);
  67. return [storedValue === undefined ? initialValue : storedValue, setValue];
  68. };
  69. export default useLocalStorage;