This article shows you how to persist your local state (ie React state) between re-render without the use of any state library
We will use the classic React counter.
If you refresh the page or unmount this component, you will see in this example that you have lost the counter value.
function Counter() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = React.useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
If you persist it in memory, the value will be deleted if the user reload the page but not when your component unmount and mount again
The trick is to use:
The counter component with a persistent in-memory value.
let memoryCount = 0;
function Counter() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = React.useState(memoryCount);
// useEffect is called at the end of the rendering and only if count has changed
React.useEffect(() => {
memoryCount = count
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
To persist the value after a page load, you need a browser storage. In this example, we use the localStorage store.
The counter component with a persistent in-browser value.
function Counter() {
let counterKey = 'counter'
const [count, setCount] = React.useState(()=> {
localStorage.getItem(counterKey)!== null ? +localStorage.getItem(counterKey): 0
});
// useEffect is called at the end of the rendering and only if count has changed
React.useEffect(() => {
localStorage.setItem(counterKey, count)
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
This is an example written in typescript on how you can extract the previous useState and useEffect hook to create your own Hook.
Example of an in-memory useState custom Hook:
let memoryState: { [key: string]: any } = {};
function useMemoryState<S>(initial: S, variableName: string) {
function getInitialState(): S {
if (memoryState[variableName] !== undefined) {
return memoryState[variableName];
}
return initial;
}
const [state, setState] = useState<S>(getInitialState)
useEffect(() => {
memoryState[variableName] = state
}, [state, variableName]);
return [state, setState] as const;
}