Have you ever filled out a form in a web app, reloaded the page, and then… poof! All your data disappeared? Annoying, right? That’s where localStorage can be a lifesaver.
In this blog post, we’ll explore what localStorage is, how it works inside a React app, and how you can build a simple CRUD (Create, Read, Update, Delete) application that stores data in the browser — permanently (well, almost). This post is perfect for beginners who want to understand how to persist data without needing a backend.
What Is localStorage?
localStorage is a browser feature that lets you store small bits of data on the user’s computer — even after they close the browser. It’s part of the Web Storage API, and unlike cookies, it doesn’t get sent with every HTTP request.
Here are a few key things to remember:
-
It stores data as key-value pairs.
-
The data is saved as strings.
-
It’s synchronous (not recommended for storing large datasets).
-
The data persists until explicitly deleted.
// Example usage:
localStorage.setItem("name", "John");
const name = localStorage.getItem("name"); // "John"
localStorage.removeItem("name");
localStorage.clear(); // clears all keys
Why Use localStorage in React?
In React, state is temporary. If you refresh the page, your state gets wiped out. But with localStorage, you can save your app’s data between page reloads — without needing a backend or database.
For simple apps like to-do lists, bookmarks, or user preferences, localStorage can handle it all.
Building a CRUD App with React and localStorage
Let’s build a mini project: a To-Do List App using React and localStorage. You’ll be able to:
-
Create tasks
-
View tasks
-
Edit tasks
-
Delete tasks
Step 1: Setting Up the React App
You can create a new React app using:
npx create-react-app react-localstorage-crud
cd react-localstorage-crud
npm start
Once that’s done, open your App.js
file and get ready to write some code!
Step 2: Create Task State and Load from localStorage
import React, { useState, useEffect } from "react";
function App() {
const [tasks, setTasks] = useState([]);
const [input, setInput] = useState("");
// Load tasks from localStorage
useEffect(() => {
const storedTasks = JSON.parse(localStorage.getItem("tasks"));
if (storedTasks) {
setTasks(storedTasks);
}
}, []);
// Save tasks to localStorage
useEffect(() => {
localStorage.setItem("tasks", JSON.stringify(tasks));
}, [tasks]);
We’re using useEffect
twice:
-
Once to load tasks on first render.
-
Again to update localStorage every time
tasks
changes.
Step 3: Create a Task
const addTask = () => {
if (input.trim() === "") return;
const newTask = { id: Date.now(), text: input, isEditing: false };
setTasks([...tasks, newTask]);
setInput("");
};
Step 4: Read & Display Tasks
const handleChange = (e) => setInput(e.target.value);
return (
<div style={{ padding: 20 }}>
<h2>React localStorage To-Do App</h2>
<input value={input} onChange={handleChange} />
<button onClick={addTask}>Add</button>
<ul>
{tasks.map((task) =>
task.isEditing ? (
<EditTask key={task.id} task={task} setTasks={setTasks} tasks={tasks} />
) : (
<li key={task.id}>
{task.text}{" "}
<button onClick={() => toggleEdit(task.id)}>Edit</button>{" "}
<button onClick={() => deleteTask(task.id)}>Delete</button>
</li>
)
)}
</ul>
</div>
);
Step 5: Update a Task
You can toggle edit mode and update the text:
const toggleEdit = (id) => {
setTasks(
tasks.map((task) =>
task.id === id ? { ...task, isEditing: true } : task
)
);
};
const updateTask = (id, newText) => {
setTasks(
tasks.map((task) =>
task.id === id ? { ...task, text: newText, isEditing: false } : task
)
);
};
Then create a separate component EditTask.js
:
import React, { useState } from "react";
function EditTask({ task, setTasks, tasks }) {
const [newText, setNewText] = useState(task.text);
const saveTask = () => {
const updated = tasks.map((t) =>
t.id === task.id ? { ...t, text: newText, isEditing: false } : t
);
setTasks(updated);
};
return (
<li>
<input value={newText} onChange={(e) => setNewText(e.target.value)} />
<button onClick={saveTask}>Save</button>
</li>
);
}
export default EditTask;
Step 6: Delete a Task
const deleteTask = (id) => {
const updated = tasks.filter((task) => task.id !== id);
setTasks(updated);
};
Tips for Using localStorage Wisely
-
Only store small data — don’t use it for images or large files.
-
Use JSON.stringify/parse to handle arrays or objects.
-
Always validate data before using it (e.g., null checks).
-
Avoid storing sensitive data — localStorage is not secure.
Final Thoughts
localStorage is a simple yet powerful way to persist data in your React apps. By combining it with React’s state and effects, you can easily build client-side applications with full CRUD functionality — no server required!
This kind of setup is great for beginners, small projects, or offline-first apps. Just remember that localStorage has limits, and for larger or collaborative apps, you’ll eventually need a proper backend.