DEV Community

Cover image for How a simple hook can save you from a lot of hassle...
Pratyush Srivastava
Pratyush Srivastava

Posted on

How a simple hook can save you from a lot of hassle...

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;
Enter fullscreen mode Exit fullscreen mode

How it works

  • The hook takes two arguments: key and defaultValue.
  • 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]);
Enter fullscreen mode Exit fullscreen mode

Now, I can replace all of that with just two lines:

const [list, setList] = useLocalStore('todos', []);
const [filterState, setFilterState] = useLocalStore('filter', 'all');
Enter fullscreen mode Exit fullscreen mode

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]);
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
link2twenty profile image
Andrew Bone

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.

Collapse
 
prs-dev profile image
Pratyush Srivastava

Appreciate it Andrew, thanks for the kind words.