DEV Community

Cover image for Simplest Custom Hook to Persist Data.
Rishabh Gupta
Rishabh Gupta

Posted on

Simplest Custom Hook to Persist Data.

I was recently filling a survey form built on Typeform (Highly recommend using) and I must say that it has an amazing UX compared to it's competitors like Google form, Microsoft form etc. The thing which got me the most hooked was, when I mistakenly closed that tab in-between and reopened it again, all my information filled before was still there. Typeform was persisting data unlike Google forms or other platforms that I have come across.

Typeform was leveraging the local storage API of the browser. So, as a React guy I so wanted to make a React hook which I can use for my future projects, taking the advantage of the local storage.

Custom hook useLocalState

Here we will be using the window.localStorage API and store the data in the local storage of the browser. Even if you close the tab and come back to the same page, your previous state will be preserved.

For this, first we will be using a useState hook with a callback function returning the value from the local storage of the browser if the data is present, Otherwise, the default value passed as a prop.

const [value, setValue] = useState(() => {
    const tempValue = window.localStorage.getItem(key);
    return tempValue !== null ? JSON.stringify(tempValue) : defaultVal;
});
Enter fullscreen mode Exit fullscreen mode

The data can be saved to the local storage with a specific key assigned to the data. You can think this of as a kind of object as well.

Next we will have to sync the data and update it if it's changed. We will be taking use of the useEffect hook for this.

useEffect(() => {
    window.localStorage.setItem(key, JSON.stringify(value));
}, [value]);
Enter fullscreen mode Exit fullscreen mode

The custom useLocalStorage hook.

import { useEffect, useState } from "react";

const useLocalStorage = (defaultVal, key) => {
  const [value, setValue] = useState(() => {
    const tempValue = window.localStorage.getItem(key);
    return tempValue !== null ? JSON.stringify(tempValue) : defaultVal;
  });

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

  return [value, setValue];
};

export default useLocalStorage;
Enter fullscreen mode Exit fullscreen mode

Example application

Let's make a simple counter with two function, increment and decrement to understand this concept.

import React from "react";

const App = () => {
  const [count, setCount] = useLocalState(0, "count");

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

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

  return (
    <div>
      <h1>Counter:</h1>
      <h2>{count}</h2>
      <button onClick={increment}>Increment (+)</button>
      <button onClick={decrement}>Decrement (-)</button>
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Try out this example.

NOTE

Do not use this hook in SSR frameworks. The local storage API shows error is SSR frameworks like (Nextjs, Gatsby etc). As it will be compiled on the server side and the local storage of the server will be referenced and not the client's browser.

Discussion (4)

Collapse
devhammed profile image
Hammed Oyedele

I created something similar but this is using the cookies for more compatibility: github.com/devhammed/use-cookie

Collapse
imrishabh18 profile image
Rishabh Gupta Author

Nice! Will check this out.

Collapse
fromnibly profile image
Jordan Davidson

You should check out hookstate. It has a plugin so you can just add persistence to any piece of state.

Collapse
morganjay profile image
James Morgan

Do you know of any docs or articles explaining and implementing hookstate?