Skip to main content

A Custom Hook for Local Storage: `useLocalStorage` (Part 1) - Persisting State in the Browser #86

📖 Introduction

Following our exploration of the useFetch hook, this article introduces another incredibly useful custom hook: useLocalStorage. We will learn how to create a hook that simplifies the process of storing and retrieving data from the browser's local storage, allowing us to persist state across browser sessions.


📚 Prerequisites

Before we begin, please ensure you have a solid grasp of the following concepts:

  • React Hooks, especially useState and useEffect.
  • The localStorage API.
  • JSON.stringify() and JSON.parse().

🎯 Article Outline: What You'll Master

In this article, you will learn:

  • The Problem: Understanding the need to persist state and the boilerplate involved in using localStorage directly.
  • Core Implementation: How to build a useLocalStorage hook from scratch.
  • Practical Application: How to use the useLocalStorage hook in a component to create a persistent counter.

🧠 Section 1: The Core Concepts of a useLocalStorage Hook

In many applications, you'll want to save some of the user's data so that it's not lost when they refresh the page or close the browser. The localStorage API allows us to do this, but using it directly in our components can be repetitive.

A useLocalStorage hook abstracts away the logic for interacting with localStorage, providing a simple and reusable way to manage persistent state. It will have an API similar to useState, but with the added benefit of automatically saving the state to localStorage.


💻 Section 2: Deep Dive - Implementation and Walkthrough

Let's build the useLocalStorage hook.

2.1 - The useLocalStorage Hook

Create a new file called useLocalStorage.js:

// useLocalStorage.js
import { useState, useEffect } from 'react';

function getStorageValue(key, defaultValue) {
const saved = localStorage.getItem(key);
const initial = JSON.parse(saved);
return initial || defaultValue;
}

function useLocalStorage(key, defaultValue) {
const [value, setValue] = useState(() => {
return getStorageValue(key, defaultValue);
});

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

return [value, setValue];
}

export default useLocalStorage;

Step-by-Step Code Breakdown:

  1. getStorageValue: This helper function retrieves the initial value from localStorage.
    • It takes a key and a defaultValue.
    • It gets the item from localStorage and parses it as JSON.
    • If no value is found, it returns the defaultValue.
  2. useLocalStorage: This is our custom hook.
    • useState: We use useState with a function as the initial value. This ensures that we only read from localStorage on the initial render.
    • useEffect: We use useEffect to update localStorage whenever the key or value changes.
    • return [value, setValue]: We return the value and setValue function, just like useState.

🛠️ Section 3: Project-Based Example: A Persistent Counter

Now, let's use our new useLocalStorage hook to create a counter that remembers its value even after a page refresh.

// PersistentCounter.js
import React from 'react';
import useLocalStorage from './useLocalStorage';

function PersistentCounter() {
const [count, setCount] = useLocalStorage('my-app-counter', 0);

return (
<div>
<h1>Persistent Counter</h1>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<button onClick={() => setCount(count - 1)}>Decrement</button>
</div>
);
}

export default PersistentCounter;

Code Breakdown:

  1. import useLocalStorage from './useLocalStorage';: We import our custom hook.
  2. const [count, setCount] = useLocalStorage('my-app-counter', 0);: We call our useLocalStorage hook with a key and a default value.
  3. We then use the count and setCount variables just like we would with a regular useState hook.

Now, if you increment or decrement the counter and then refresh the page, the count will be preserved.


💡 Conclusion & Key Takeaways

Congratulations! You've created a powerful useLocalStorage hook that simplifies the process of persisting state in your React applications.

Let's summarize the key takeaways:

  • The useLocalStorage hook provides a simple and reusable way to manage persistent state.
  • It has an API that is similar to useState, making it easy to use.
  • By creating a useLocalStorage hook, you can make your state management logic more consistent and easier to maintain.

Challenge Yourself: To solidify your understanding, try to create a simple theme switcher component that uses the useLocalStorage hook to persist the selected theme.


➡️ Next Steps

You now have a solid understanding of how to create a useLocalStorage hook. In the next article, "A Custom Hook for Local Storage: useLocalStorage (Part 2)", we will explore how to handle objects and arrays in local storage and how to sync state between different tabs.

Thank you for your dedication. Stay curious, and happy coding!


glossary

  • useLocalStorage: A custom hook for persisting state in the browser's local storage.
  • localStorage: A web storage API that allows you to store key-value pairs in a web browser with no expiration date.
  • JSON.stringify(): A JavaScript method that converts a JavaScript object or value to a JSON string.
  • JSON.parse(): A JavaScript method that parses a JSON string, constructing the JavaScript value or object described by the string.

Further Reading