Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import { useState } from 'react';
// Usage
function App() {
// Similar to useState but first arg is key to the value in local storage.
const [name, setName] = useLocalStorage('name', 'Bob');
return (
<div>
<input
type="text"
placeholder="Enter your name"
value={name}
onChange={e => setName(e.target.value)}
/>
</div>
);
}
// Hook
function useLocalStorage(key, initialValue) {
// State to store our value
// Pass initial state function to useState so logic is only executed once
const [storedValue, setStoredValue] = useState(() => {
try {
// Get from local storage by key
const item = window.localStorage.getItem(key);
// Parse stored json or if none return initialValue
return item ? JSON.parse(item) : initialValue;
} catch (error) {
// If error also return initialValue
console.log(error);
return initialValue;
}
});
// Return a wrapped version of useState's setter function that ...
// ... persists the new value to localStorage.
const setValue = value => {
try {
// Allow value to be a function so we have same API as useState
const valueToStore =
value instanceof Function ? value(storedValue) : value;
// Save state
setStoredValue(valueToStore);
// Save to local storage
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
// A more advanced implementation would handle the error case
console.log(error);
}
};
return [storedValue, setValue];
}
@vitkon

This comment has been minimized.

Copy link

vitkon commented Oct 29, 2018

Is localStorage read on every rerender?

@skiano

This comment has been minimized.

Copy link

skiano commented Oct 29, 2018

I wonder if it would be an improvement to write to local storage inside useEffect so that it runs after the render finished?

@gragland

This comment has been minimized.

Copy link
Owner Author

gragland commented Oct 29, 2018

@vitkon Local storage should only be read on the first render since I'm passing a function to useState. Unless I'm missing something..

@bduimstra

This comment has been minimized.

Copy link

bduimstra commented Oct 29, 2018

I would also suggest wrapping localStorage calls in a try/catch block to avoid any unwanted side effects.

@andys8

This comment has been minimized.

Copy link

andys8 commented Oct 29, 2018

useEffect was said to be for side effects. Accessing and manipulating local storage is a side effect.

Mutations, subscriptions, timers, logging, and other side effects are not allowed inside the main body of a function component (referred to as React’s render phase). Doing so will lead to confusing bugs and inconsistencies in the UI.
https://reactjs.org/docs/hooks-reference.html#useeffect

@deomsj

This comment has been minimized.

Copy link

deomsj commented Oct 29, 2018

love what you are doing here. thank you for sharing this!

one suggestion, could we swap out this:

const [item, setValue] = useState(() =>
    window.localStorage.getItem(key) !== null
      ? window.localStorage.getItem(key)
      : initialValue);

with this, for readability:

const [item, setValue] = useState(() => window.localStorage.getItem(key) || initialValue);

Looking forward to more recipes. I'm already hooked after just one :)

@gragland

This comment has been minimized.

Copy link
Owner Author

gragland commented Oct 29, 2018

@skiano @andys8 Good call. Just updated it to use useEffect instead. Thanks!

@gragland

This comment has been minimized.

Copy link
Owner Author

gragland commented Oct 29, 2018

@deomsj Glad you're liking it and good suggestion! Updated :)

@TortleWortle

This comment has been minimized.

Copy link

TortleWortle commented Oct 29, 2018

I like the recipe but there is an issue when using numbers and that they will convert to strings after a refresh. Maybe it is an idea to encode and decode as JSON ?

@AndyBarron

This comment has been minimized.

Copy link

AndyBarron commented Oct 30, 2018

Suggestion: Return a wrapped version of setValue that updates localStorage whenever it's called. With the current setup, localStorage will be written to on every render, which I don't imagine is fast!

@AndyBarron

This comment has been minimized.

Copy link

AndyBarron commented Oct 30, 2018

Suggested changes:

import { useState } from 'react';

// Usage
function App() {
  // Similar to useState but we pass in a key to value in local storage
  // With useState: const [name, setName] = useState('Bob');
  const [name, setName] = useLocalStorage('name', 'Bob');

  return (
    <div>
      <input
        type="text"
        placeholder="Enter your name"
        value={name}
        onChange={e => setName(e.target.value)}
      />
    </div>
  );
}

// Hook
const useLocalStorage = (key, initialValue) => {
  // The initialValue arg is only used if there is nothing in local storage ...
  // ... otherwise we use the value in local storage so state persist through a page refresh.
  // We pass a function to useState so local storage lookup only happens once.
  const [item, setInnerValue] = useState(
    () => {
      if (window.localStorage.hasItem(key)) {
        try {
          return JSON.parse(window.localStorage.getItem(key));
        } catch (error) {
          // Do nothing
        }
      }
      // Return default value if key is absent or JSON parsing fails
      return initialValue;
    },
  );

  // Return a wrapped version of useState's setter function that persists the new value to
  // localStorage.
  const setValue = (value) => {
    setInnerValue(value);
    window.localStorage.setItem(key, JSON.stringify(item));
  };

  return [item, setValue];
};
@gragland

This comment has been minimized.

Copy link
Owner Author

gragland commented Oct 30, 2018

@AndyBarron So originally I had a wrapped function like you suggest but was getting some feedback that useEffect was the right way to do it. Now that I think about it, the wrapped function seems fine since it's not being run during render. So the two choices I see:

Your suggestion:

const setValue = (value) => {
  setInnerValue(value);
  window.localStorage.setItem(key, JSON.stringify(item));
};

Or make it an effect but pass array of values that need to change for it to be called:

useEffect(() => {
  window.localStorage.setItem(key, JSON.stringify(item));
},[key, item]);

Any thoughts on which would be the better choice? Anyone feel free to weigh in here.

@skiano

This comment has been minimized.

Copy link

skiano commented Oct 30, 2018

This is sort of a tangent, but Philip Walton's article about idle until urgent was so inspiring that I can't help but think about it here

https://philipwalton.com/articles/idle-until-urgent/#persisting-application-state

For small cases this gist seems good, but if its being used inside a game or something that is more intensive, I wonder if it worth considering the pattern outlined under the "Persisting application state" example in the article (using an IdleQueue). I'm not suggesting that the gist change :) just thinking its worth considering before plugging this into an app.

@AndyBarron

This comment has been minimized.

Copy link

AndyBarron commented Oct 30, 2018

@gragland Another issue with useEffect is that it will immediately persist the default value to localStorage on mount, which might not be what you want. The wrapped version will only write to storage when setValue is called. I would consider the wrapped version better for this reason as well.

@gragland

This comment has been minimized.

Copy link
Owner Author

gragland commented Oct 30, 2018

@AndyBarron Yeah good point, okay going with the wrapped version. I changed your code slightly so that all calls to localStorage are within the try/catch.

  const [item, setInnerValue] = useState(() => {
    try {
      return window.localStorage.getItem(key)
        ? JSON.parse(window.localStorage.getItem(key))
        : initialValue;
    } catch (error) {
      // Return default value if JSON parsing fails
      return initialValue;
    }
  });
@ianobermiller

This comment has been minimized.

Copy link

ianobermiller commented Nov 9, 2018

Proposed updates:

  • You can wrap setValue with useCallback to ensure you don't return new setValue functions on every render
  • I think it should be stringifying value, not item
  • Might as well wrap this one in try-catch as well (and stringify might throw too)
  • call setInnerValue after localstorage in case persistence throws, so you will not silently think it is working
  const setValue = useCallback(value => {
    try {
      window.localStorage.setItem(key, JSON.stringify(value));
      setInnerValue(value);
    } catch (e) {
      console.log(e);
    }
  }, [setInnerValue]);
@gustavoguichard

This comment has been minimized.

Copy link

gustavoguichard commented Nov 12, 2018

Cool lil code =)
The localStorage is storing the previous state though, you must change line 42 for using value instead of item:

window.localStorage.setItem(key, JSON.stringify(value));

So it'll actually save the value that is reflected in the input ;)

@sabir-jamia

This comment has been minimized.

Copy link

sabir-jamia commented Nov 23, 2018

Cool lil code =)
The localStorage is storing the previous state though, you must change line 42 for using value instead of item:

window.localStorage.setItem(key, JSON.stringify(value));

So it'll actually save the value that is reflected in the input ;)

I also think, it should be value instead of item. By doing this , If we refresh the page the value remains the same in the input box.

@Beraliv

This comment has been minimized.

Copy link

Beraliv commented Nov 24, 2018

@sabir-jamia is right as you save previous version of a string

@rista404

This comment has been minimized.

Copy link

rista404 commented Jan 24, 2019

As @gustavoguichard said, it should be window.localStorage.setItem(key, JSON.stringify(value)); on line 42, not item

@turdiyev

This comment has been minimized.

Copy link

turdiyev commented Feb 7, 2019

Yep, should be value, not item.

BTW, If you need typescript code, here you are:

import { useState, Dispatch, SetStateAction } from 'react';


export default function <S>(
    key: string,
    initialValue?: S
): [S, Dispatch<SetStateAction<S>>] {
    // The initialValue arg is only used if there is nothing in localStorage ...
    // ... otherwise we use the value in localStorage so state persist through a page refresh.
    // We pass a function to useState so localStorage lookup only happens once.
    // We wrap in try/catch in case localStorage is unavailable
    const [item, setInnerValue] = useState<S>(() => {
        try {
            const valueItem = window.localStorage.getItem(key);
            return valueItem ? JSON.parse(valueItem) : initialValue;
        } catch (error) {
            // Return default value if JSON parsing fails
            return initialValue;
        }
    });

    // Return a wrapped version of useState's setter function that ...
    // ... persists the new value to localStorage.
    const setValue = (value: SetStateAction<S>): SetStateAction<S> => {
        setInnerValue(value);
        window.localStorage.setItem(key, JSON.stringify(value));
        return value;
    };

    // Alternatively we could update localStorage inside useEffect ...
    // ... but this would run every render and it really only needs ...
    // ... to happen when the returned setValue function is called.
    /*
    useEffect(() => {
      window.localStorage.setItem(key, JSON.stringify(item));
    });
    */

    return [item, setValue];
}
@gragland

This comment has been minimized.

Copy link
Owner Author

gragland commented Feb 7, 2019

Thanks for the feedback everyone! Just updated the recipe to fix the usage of item instead of value and now wrapping the second local storage call in a try/catch.

@gragland

This comment has been minimized.

Copy link
Owner Author

gragland commented Feb 11, 2019

Just updated so value passed to setValue can also be a function that gets passed current state (just like useState).

@oleg-am

This comment has been minimized.

Copy link

oleg-am commented Mar 28, 2019

We have wrong behavior, if in localStorage saved string value without JSON.stringify
Example: window.locslStorage.setItem('someKey', 'stringValue')

This code will return initial value, because JSON.parse(item) will caused error.
But we need item.

try {
      // Get from local storage by key
      const item = window.localStorage.getItem(key);
      // Parse stored json or if none return initialValue
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      // If error also return initialValue
      console.log(error);
      return initialValue;
    }

We need return item from catch block, and change area of try block:

      // Get from local storage by key
      const item = window.localStorage.getItem(key);
try {
      // Parse stored json or if none return initialValue
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      // If error return item
      console.log(error);
      return item;
    }
@beausmith

This comment has been minimized.

Copy link

beausmith commented May 17, 2019

I wish I had seen @turdiyev's post here before I had written my own TypeScript version of this useLocalStorage hook.

This version is similar, with exceptions:

  • doesn't have try/catch blocks (simple to add back in if needed).
  • removes the localStorage if value to store is "falsey".
  • named useStateWithLocalStorage to be more explicit.
// useStateWithLocalStorage.ts

import { useState, Dispatch, SetStateAction } from 'react'

const useStateWithLocalStorage = <S>(
  key: string,
  initialValue?: S
): [S, Dispatch<SetStateAction<S>>] => {
  const [item, setInnerValue] = useState<S>(() => {
    const valueItem = window.localStorage.getItem(key)
    return valueItem ? JSON.parse(valueItem) : initialValue
  })

  const setValue = (value: SetStateAction<S>): SetStateAction<S> => {
    const valueToStore = value instanceof Function ? value(item) : value
    setInnerValue(valueToStore)
    if (valueToStore) {
      window.localStorage.setItem(key, JSON.stringify(valueToStore))
    } else {
      window.localStorage.removeItem(key)
    }
    return value
  }

  return [item, setValue]
}

export default useStateWithLocalStorage

PS - @turdiyev - Thanks for your example above; I learned a couple things!

@turdiyev

This comment has been minimized.

Copy link

turdiyev commented May 18, 2019

@beausmith. You are welcome. I'm glad to help you

@jildertvenema

This comment has been minimized.

Copy link

jildertvenema commented Jul 12, 2019

Suggested change:

if value is null or undefined remove it from local storage.

import { useState } from 'react'

// Hook
function useLocalStorage (key, initialValue) {
  // State to store our value
  // Pass initial state function to useState so logic is only executed once
  const [storedValue, setStoredValue] = useState(() => {
    try {
      // Get from local storage by key
      const item = window.localStorage.getItem(key)
      // Parse stored json or if none return initialValue
      return item ? JSON.parse(item) : initialValue
    } catch (error) {
      // If error also return initialValue
      console.log(error)
      return initialValue
    }
  })

  // Return a wrapped version of useState's setter function that ...
  // ... persists the new value to localStorage.
  const setValue = value => {
    try {
      // Allow value to be a function so we have same API as useState
      const valueToStore =
        value instanceof Function ? value(storedValue) : value
      // Save state
      setStoredValue(valueToStore)
      // Save to local storage or remove if value is null or undefined
      if (valueToStore === null || valueToStore === undefined) {
        window.localStorage.removeItem(key)
      } else {
        window.localStorage.setItem(key, JSON.stringify(valueToStore))
      }
    } catch (error) {
      // A more advanced implementation would handle the error case
      console.log(error)
    }
  }

  return [storedValue, setValue]
}

export default useLocalStorage
@vinicius98s

This comment has been minimized.

Copy link

vinicius98s commented Aug 8, 2019

As said by @oleg-am when you try to parse a string from localStorage you get an error, but we still want to return the initalValue if it doesn't exist so we can call an external function to verify this

The same occurs if you try to stringify a string, so when try to save it on localStorage verify if it already is a string

const useLocalStorage = (key, initialValue) => {
  const parseJsonItem = item => {
    try {
      return JSON.parse(item);
    } catch (e) {
      return item;
    }
  };

  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);

      if (item) return parseJsonItem(item);

      return initialValue;
    } catch (error) {
      console.error(error);
      return initialValue;
    }
  });

  const setValue = value => {
    try {
      const valueToStore =
        value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(
        key,
        typeof valueToStore === 'string'
          ? valueToStore
          : JSON.stringify(valueToStore),
      );
    } catch (error) {
      console.error(error);
    }
  };

  return [storedValue, setValue];
};
@jazzfog

This comment has been minimized.

Copy link

jazzfog commented Oct 4, 2019

Maybe I am missing something, but why isn't it as simple as this?

TypeScript:

import { useCallback, useEffect, useState } from 'react';

const parseJson = <T>(str: string | null | undefined): T | undefined => {
  try {
    return JSON.parse(str as string);
  } catch (e) {
    return undefined;
  }
};

export const useLocalStorage = <T>(key: string, initialValue: T): [T, (value: T) => void] => {

  const defaultGetter = useCallback(() => {
    const parsed = parseJson<T>(localStorage.getItem(key));
    return parsed === undefined || parsed === null ? initialValue : parsed;
  }, [ key, initialValue ]);

  const [ value, setValue ] = useState<T>(defaultGetter);

  useEffect(
    () => localStorage.setItem(key, JSON.stringify(value)),
    [ value, key ]
  );

  return [ value, setValue ];
};
  • I know, it is not recommended to access the external resources outside of useEffect but in this case it might be important to render the first time with the correct value from the localStorage so can't put the reading part there. In my case component re-render causes flashing so I can't allow second re-render (when default value change to the one from localStorage) need the value right away, I presume this could be the case for others as well.
@jephjohnson

This comment has been minimized.

Copy link

jephjohnson commented Feb 12, 2020

Hi @gragland - Have you ran into any scenarios where local-storage is needed on more than one element?

I am running into the state being updated on two elements and they both need to be isolated of each other. The error is both counters keep duplicating each others values. That shouldn't be the intended behavior

Ex: https://codesandbox.io/s/stoic-satoshi-owsu9

@jildertvenema

This comment has been minimized.

Copy link

jildertvenema commented Feb 13, 2020

@jephjohnson
I have made a solution for you using react's context.
Only thing you have to add is the LocalStorageProvider in your app.js

Here is a working example: https://codesandbox.io/s/zealous-bell-o6lh9

This is my use-local-storage.js:

import React, { useState, createContext, useContext } from "react";

export const localStorageContext = createContext();
export const useLocalStorageContext = () => useContext(localStorageContext);
export const LocalStorageProvider = ({ children }) => {
  const [state, setState] = useState({});
  return (
    <localStorageContext.Provider value={{ state, setState }}>
      {children}
    </localStorageContext.Provider>
  );
};

export default function useLocalStorage(key, initialValue) {
  const { state, setState } = useLocalStorageContext();

  let value = state[key];

  if (!value) {
    try {
      // Get from local storage by key
      const item = window.localStorage.getItem(key);
      // Parse stored json or if none return initialValue
      value = item ? JSON.parse(item) : initialValue;
    } catch (error) {
      // If error also return initialValue
      console.log(error);
      return initialValue;
    }
  }

  // Return a wrapped version of useState's setter function that ...
  // ... persists the new value to localStorage.
  const setValue = value => {
    try {
      // Allow value to be a function so we have same API as useState
      const valueToStore =
        value instanceof Function ? value(state[key]) : value;
      // Save state
      setState(prev => ({ ...prev, [key]: valueToStore }));

      // Save to local storage
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      // A more advanced implementation would handle the error case
      console.log(error);
    }
  };

  return [value, setValue];
}

And this is your app.js:

import React, { useState, useEffect } from "react";
import useLocalStorage from "./use-local-storage";
import { LocalStorageProvider } from "./use-local-storage";

const navLinks = [{ text: "Cars" }, { text: "Buses" }];

const Items = ({ text, id, activeTab }) => {
  const [count, setCount] = useLocalStorage("count", 0);

  const plus = () => {
    setCount(count + 1);
  };

  const minus = () => {
    setCount(count - 1);
  };

  return (
    <div id={id} className={activeTab === id ? "active" : null}>
      {text}
      <h2>You clicked {count} times!</h2>
      <button onClick={plus}>+</button>
      <button onClick={minus}>-</button>
    </div>
  );
};

const Nav = ({ list, activeTab, onClick }) => {
  return list ? (
    list.map((item, index) => (
      <Items
        key={index}
        text={item.text}
        onClick={onClick}
        activeTab={activeTab}
      />
    ))
  ) : (
    <div>No Data</div>
  );
};

function App() {
  const [items, setlist] = useState([]);

  useEffect(() => {
    setlist(navLinks);
  }, []);

  return (
    <LocalStorageProvider>
      <Nav list={items} />
    </LocalStorageProvider>
  );
}
export default App;

Hi @gragland - Have you ran into any scenarios where local-storage is needed on more than one element?

I am running into the state being updated on two elements.

Ex: https://codesandbox.io/s/stoic-satoshi-owsu9

@jephjohnson

This comment has been minimized.

Copy link

jephjohnson commented Feb 13, 2020

@jildertvenema - Doh! Looks like both counters are being updated at the same time. They should both be isolated. So if Increment the counter on the first one, refresh the value should persist. The second one should not duplicate the same value. Make sense? Both are independent of each other

@jildertvenema

This comment has been minimized.

Copy link

jildertvenema commented Feb 14, 2020

@jephjohnson Then why not use count1 and count2?

@jephjohnson

This comment has been minimized.

Copy link

jephjohnson commented Feb 14, 2020

@jephjohnson Then why not use count1 and count2?

In the state? Not following...

@jildertvenema

This comment has been minimized.

Copy link

jildertvenema commented Feb 18, 2020

@jephjohnson Maybe i'm missing your point but why don't u use useLocalStorage("bussesCount", 0); and useLocalStorage("carCount", 0);

@jephjohnson

This comment has been minimized.

Copy link

jephjohnson commented Feb 19, 2020

@jephjohnson Maybe i'm missing your point but why don't u use useLocalStorage("bussesCount", 0); and useLocalStorage("carCount", 0);

Codesandbox on what your thinking would be helpful

@jephjohnson

This comment has been minimized.

Copy link

jephjohnson commented Mar 1, 2020

@jildertvenema - I am duplicating the component. What are you thinking exactly?

@jildertvenema

This comment has been minimized.

@jildertvenema

This comment has been minimized.

Copy link

jildertvenema commented Mar 2, 2020

@jephjohnson i've added a stateName property to your tabs

@jephjohnson

This comment has been minimized.

Copy link

jephjohnson commented Mar 3, 2020

@jephjohnson i've added a stateName property to your tabs

@jildertvenema - Epic! Solid idea :)

@trixn86

This comment has been minimized.

Copy link

trixn86 commented Apr 14, 2020

There is a flaw in the way this hook tries to emulate useState behaviour.

React batches calls to setState that happen in the same callback. Because of that you should never rely on the state returned by useState to update the state. This is why you can also pass a function to setState that receives the latest state as an argument. But this is actually broken here because the hook invokes the function with the state returned by useState which may already be outdated from a previous call. Instead it should simply pass the function provided to setStoredValue and update the local storage with the resulting state when it has been updated using useEffect.

Also see Why is setState giving me the wrong value?.

Have a look at this example to see the problem:

const BrokenCounter = () => {
  const [count, setCount] = useLocalStorage("count", 0);

  const handleIncrement = () => {
    // count should be increased by 2
    // but it will only be increased by 1 because react batches those updates
    // https://reactjs.org/docs/faq-state.html#why-is-setstate-giving-me-the-wrong-value
    setCount(current => current + 1);
    setCount(current => current + 1);
  };

  return (
    <div>
      <p>{`The count is: ${count}`}</p>
      <button onClick={handleIncrement}>Increment by 2</button>
    </div>
  );
}

Edit restless-leftpad-q3e6j

This is my suggestion for a fix:

function useLocalStorage(key, initialValue) {
  // State to store our value
  // Pass initial state function to useState so logic is only executed once
  const [storedValue, setStoredValue] = useState(() => {
    try {
      // Get from local storage by key
      const item = window.localStorage.getItem(key);
      // Parse stored json or if none return initialValue
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      // If error also return initialValue
      console.log(error);
      return initialValue;
    }
  });

  useEffect(() => {
    try {
      // Save to local storage
      window.localStorage.setItem(key, JSON.stringify(storedValue));
    } catch (error) {
      // A more advanced implementation would handle the error case
      console.log(error);
    }
  }, [key, storedValue]);

  return [storedValue, setStoredValue];
}

Edit proud-morning-bhfq1

@sanyuelanv

This comment has been minimized.

Copy link

sanyuelanv commented May 7, 2020

if you want this link

import { useState } from 'react';

// Usage
function App() {
  // Similar to useState but first arg is key to the value in local storage.
  const [name, setName] = useLocalStorage('name', 'Bob');

  return (
    <div>
      <input
        type="text"
        placeholder="Enter your name"
        value={name}
        onChange={e => setName(e.target.value)}
      />
    </div>
  );
}

// Hook
function useLocalStorage(key, initialValue) {
  // State to store our value
  // Pass initial state function to useState so logic is only executed once
  const [storedValue, setStoredValue] = useState(() => {
    try {
      // Get from local storage by key
      const item = window.localStorage.getItem(key);
      // Parse stored json or if none return initialValue
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      // If error also return initialValue
      console.log(error);
      return initialValue;
    }
  });

  // Return a wrapped version of useState's setter function that ...
  // ... persists the new value to localStorage.
  const setValue = value => {
    try {
      // if you want the real function
      let valueToStore
      if(value instanceof Function){
        setStoredValue((v) => {
          valueToStore = value(v)
          return valueToStore
        })
      }
      else{
        valueToStore = value
        setStoredValue(value)
      }
      // Allow value to be a function so we have same API as useState
      //const valueToStore = value instanceof Function ? value(storedValue) : value;
      // Save state
      //setStoredValue(valueToStore);
      // Save to local storage
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      // A more advanced implementation would handle the error case
      console.log(error);
    }
  };

  return [storedValue, setValue];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.