Unlock the Power of Pinia LocalStorage with Pinia Persist
Posted September 9, 2023
Pinia lacks Persisted states. Dive in, use Pinia Persist to LocalStorage in this Pinia LocalStorage example and shine Pinia with persistent
Pinia manages the states of the Vue.js app. However, it doesn’t persist data saved across the states. Now, enter Pinia LocalStorage integration. This dynamic duo ensures your state remains intact even after the page refreshes.
In this guide, you will learn an elegant way of using Pinia LocalStorage and say goodbye to losing any Pinia store throughout page reloads.
Prerequisites
Before delving into this hands-on guide, ensure you have set up a Vue app with Pinia. If Not, Check my Comprehensive Guide to Vue.js State Management using Pinia. If you love TypeScript, This Pinia store and typescript guide has you covered.
Pinia Persist and LocalStorage Duo
State management doesn’t have to be complicated, and Pinia is perfect for making your Vue.js state management smooth.
To explore the magic pineapple (I mean Pinia ๐) possibilities ๐, It may require you to persist in its states, and Pinia doesn’t have persistence support. Pinia can sore its states inside the LocalStorage of your browser with minor twerks.
Example of Non-persistent Pinia Store
The following example used Pinia to create a TodoStore
:
import { defineStore } from "pinia";
export const useTodoStore = defineStore("todo", {
state: () => ({
todos: [],
}),
actions: {
add() {
if (!this.todoMessage) return (this.error = true);
const todoData = {
id: Math.floor(Math.random() * 1000),
title: this.todoMessage,
complete: false,
};
this.todos.push(todoData);
},
update(id, status) {
const index = this.todos.findIndex((item) => item.id === id);
this.todos[index] = { ...this.todos[index], complete: status };
},
remove(id) {
this.todos = this.todos.filter((item) => item.id !== id);
},
},
getters: {
getTodos: (state) => state.todos,
hasError: (state) => state.error,
},
});
Now, this store creates the following basic todo app (I have hosted the full code on GitHub):
If you have created such an app using Pinia, the added states will be lost once you hit a page reload. Meaning the states still need to be persisted.
Now, let’s solve this problem using Pinia LocalStorage.
Persisting Pinia inside LocalStorage
Local storage features the clientโs browser to store web app data. You can use this approach and persist Pinia states. This way, Local storage will always state persistence even on page refreshes or after the browser is closed.
Let’s see Pinia and LocalStorage in action. Pinia uses:
- Key property to read the object of the
state
:
state: () => ({
todos: [],
}),
actions
to create mutations that update the state.
These two represent the lifecycle of the Pinia state and how it changes the state data. To persist pinia, they will be the main focus the LocalStorage needs access to.
At the same time, LocalStorage uses:
localStorage.setItem(key, value)
to store data in the local storage space of a browser. This method is closely related toactions
in PinialocalStorage.getItem(key)
to read the data you have saved in the browser. This scenario repsent objecttodos: []
to thestate
property.
With this understanding, you can take your Pinia sore and add localStorage in the following steps.
Step One: Creating Pinia localStorage action
The first step to persisting pinia is allowing localStorage access to the states that pinia saves using a Pinia action.
Inside your actions
create a saveTodos
method so localStorage.setItem
stores the todos array in the local storage. Your saveTodos
will be as follows:
saveTodos() {
localStorage.setItem("todos", JSON.stringify(this.todos));
},
Considering localStorage.setItem(key, value)
, todos
is the key under which your todos data will be stored in local storage, taking the value
of this.todos
containing the todo items.
You must understand that localStorage will always store data as strings. Your Pinia store saves todo items todos: []
in an array. JSON.stringify()
will take care of converting your this.todos
array to a string that localStorage can understand.
Step Two: Persisting Pinia actions to localStorage
In the useTodoStore
Pinia store, you have the following actions (once you have added saveTodos()
):
actions: {
saveTodos() {
localStorage.setItem("todos", JSON.stringify(this.todos));
},
add() {
if (!this.todoMessage) return (this.error = true);
const todoData = {
id: Math.floor(Math.random() * 1000),
title: this.todoMessage,
complete: false,
};
this.todos.push(todoData);
},
update(id, status) {
const index = this.todos.findIndex((item) => item.id === id);
this.todos[index] = {
...this.todos[index],
complete: status,
};
},
remove(id) {
this.todos = this.todos.filter((item) => item.id !== id);
},
},
In your example, every time remove(id)
, update(id, status)
, and add()
are called, the state will, of course, get the update. These calls should be captured and persisted, so if a new todo is added, calling add()
localStorage will store it.
Here is what you must do to persist in these actions
. Just call the saveTodos
method in each action and save the most current state as follows:
actions: {
saveTodos() {
localStorage.setItem("todos", JSON.stringify(this.todos));
},
add() {
if (!this.todoMessage) return (this.error = true);
const todoData = {
id: Math.floor(Math.random() * 1000),
title: this.todoMessage,
complete: false,
};
this.todos.push(todoData);
this.saveTodos();
},
update(id, status) {
const index = this.todos.findIndex((item) => item.id === id);
this.todos[index] = {
...this.todos[index],
complete: status,
};
this.saveTodos();
},
remove(id) {
this.todos = this.todos.filter((item) => item.id !== id);
this.saveTodos();
},
},
Rerun your Pinia state app. This time, add change to the actions
method will be stored by localStorage. To verify such, go to your browser inspect, and under Application, check your localStorage as follows:
Hit your page reload, and see if Pinia will load your saved localStorage data.
On page refresh, you will realize that the localStorage persisted in your pinia state. However, Pinia can’t get to display the persisted localStorage. And you have to add the final check.
Step Three: Fetching Pinia persistent localStorage data
Remember, localStorage uses localStorage.getItem(key)
to read the data you persited with Pinia in the browser. This scenario repsent object todos: []
to the state
property.
In this step, todos: []
must point to localStorage.getItem)
to read and display the localStorage data to any page reload.
state: () => ({
todos: [],
}),
Will be replaced as such:
state: () => ({
todos: JSON.parse(localStorage.getItem("todos")) || [],
}),
It’s pretty simple here. Pinia state
property and its todos
object will read the todos
on the browser. And because states return an array of the items, JSON.parse
will read the JSON Localstorage into the array todos: []
.
Conclusion
Any time you reload your page states, you will have persistent pinia inside the Local storage.
Now that you have learned how to create persistent Pinia with Local storage, why now expand your newfound knowledge and unlock the door to a new level of Pinia state management with the following topics: