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;
});
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]);
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;
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;
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.
Top comments (4)
I created something similar but this is using the cookies for more compatibility: github.com/devhammed/use-cookie
Nice! Will check this out.
You should check out hookstate. It has a plugin so you can just add persistence to any piece of state.
Do you know of any docs or articles explaining and implementing hookstate?