I'm still working on my TODO app and building it little by little. I shared my first post here:
Here it is: https://dev.to/prs-dev/manually-updating-a-list-in-localstorage-or-using-useeffect-which-is-better-2jil
A fellow developer, @link2twenty, suggested a helpful custom hook: @blocdigital/uselocalstorage. It's a great option if you're looking for a ready-made solution.
But this got me thinking—why not try building a simple custom hook myself? It wouldn’t be as advanced, but it would be enough for my use case.
So I went ahead and built a custom hook that saves me some effort.
Here's the code
import { useEffect, useState } from "react";
const useLocalStore = (key, defaultValue = '') => {
const [value, setValue] = useState(() => {
const storedValue = localStorage.getItem(key);
if (storedValue) {
return JSON.parse(storedValue);
}
return defaultValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
};
export default useLocalStore;
How it works
- The hook takes two arguments:
key
anddefaultValue
. - If no stored value is found in localStorage, it uses the default.
- It uses lazy initialization to avoid unnecessary re-renders on first load.
- Then it checks localStorage for a saved value. If found, that becomes the state value. If not, the default is used.
- Finally, a
useEffect
writes the value to localStorage whenever the key or value changes.
Real-life use in my TODO app
Before, I had this code:
useEffect(() => {
const newList = localStorage.getItem('todos');
const filter = localStorage.getItem('filter');
if (newList) setList(JSON.parse(newList));
}, []);
useEffect(() => {
if (firstRender.current) {
firstRender.current = false;
return;
}
localStorage.setItem('todos', JSON.stringify(list));
}, [list]);
useEffect(() => {
localStorage.setItem('filter', filterState);
}, [filterState]);
Now, I can replace all of that with just two lines:
const [list, setList] = useLocalStore('todos', []);
const [filterState, setFilterState] = useLocalStore('filter', 'all');
Optional: Better error handling
You can improve the hook with error handling using a try/catch
block like this:
useEffect(() => {
try {
localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.error("Error writing to localStorage key:", key);
}
}, [key, value]);
Thanks for reading.
Hope this helps someone out there! You can follow me for more dev tips and projects, next will be the todo app itself, so stay tuned.
Top comments (2)
Great work! It's super important to be able to write your own stuff or at least under how you could/would write your own.
Appreciate it Andrew, thanks for the kind words.