Refresh-proof your Pinia Stores
Tags: coding, pinia, javascript, vue
Published: 2022-10-31 16:50:25

---
title: Refresh-proof your Pinia Stores
published: true
date: 2022-10-31 10:00:03 UTC
tags: coding,pinia,javascript,vuejs
canonical_url: https://www.vuemastery.com/blog/refresh-proof-your-pinia-stores/
---

![Refresh-proof your Pinia Stores](https://cdn-images-1.medium.com/max/1024/1*USJq8xfGaa4QXSGhEY29VQ.jpeg)

_Written by_ [_David Nwadiogbu_](https://twitter.com/CNwadiogbu)

A common use case for all data stores is a need to persist data. That way, if a user refreshes the page or begins a new session we can store (persist) the current state and use it later on when the user comes back.

While Vue’s state management library, Pinia, has a lot of great features, it does not automatically persist application state. So how do you persist Pinia state upon a browser refresh? In this tutorial, we’ll be exploring three different ways you can refresh-proof your Pinia stores.

### Project Setup

To get started, if you don’t already have Pinia installed in your Vue app, add it now. In the root directory, run the following command to install Pinia:

```jsx
yarn add pinia

# or with npm
npm install pinia
```

Then update your main.js to use Pinia:

📄 **main.js**

```jsx
import { createApp } from "vue";
import { createPinia } from "pinia";
import App from "./App.vue";

const app = createApp(App);
const pinia = createPinia();

app.use(pinia);
app.mount("#app");
```

Create a stores folder under src and add a file called counter.js with the following code:

📁 **src/stores/counter.js**

```jsx
import { defineStore } from "pinia";

export const useCounterStore = defineStore("counter", {
  state: () => {
    return { 
      count: 0
     };
  },
  actions: {
    increment(value = 1) {
      this.count += value;
    },
    decrement(value = 1) {
      this.count -= value;
    },
    reset() {
      this.count = 0;
    }
  },
  getters: {
    doubleCount: (state) => {
      return state.count * 2;
    },
    squareCount: (state) => {
      return state.count ** 2;
    },
  },
});
```

We’ve created a state called count with multiple actions and getters that can dictate our state’s behavior.

Let’s display this in our app to test that it works.

Update your App.vue file to look like this:

📁 **src/App.vue**

```html
<script setup>
import { useCounterStore } from "./stores/counter"

const store = useCounterStore(); _//initialize the store_

</script>

<template>
  <h1>Counter App</h1>
  <p>Count is {{ store.count }}</p>
  <p>Double count is {{ store.doubleCount }}</p>

  <button @click="store.increment(1)">Add</button>
  <button @click="store.decrement(1)">Subtract</button>
  <button @click="store.reset">Reset</button>
</template>

<style scoped>
</style>
```

When we run the app, everything works as it should, but when we reload our page, the value of count gets reset to its initial state: 0.

There is nothing broken here; Pinia does not by itself persist the state. If that’s the behavior we want, we have to solve for that ourselves. So let’s look at different ways we can solve this problem by persisting our store upon page reloads.

### using Watch

The most common way to persist values is to save them in local storage and use the saved values to hydrate our Pinia store when the app loads.

We can use the watch method from Vue to achieve this.

Update your main.js to include the following code:

```jsx
import { createApp, watch } from "vue";
...

watch(
  pinia.state,
  (state) => {
    localStorage.setItem("counter", JSON.stringify(state.counter));
  },
  { deep: true }
  );
```

and update your counter.js to include the following code:

```jsx
state: () => {
    if (localStorage.getItem("counter"))
      return JSON.parse(localStorage.getItem("counter"));
    return {
      count: 0,
    };
  },
```

Let’s examine what our code is doing here. In the first code block, we use the watch method to detect when there are changes to our state. If there’s a change, we want to update our localStorage with this change. In the second code block, after our store is created, we check if there’s already a value for our counter state in localStorage. If there is, we then set that value to our initial value for our counter.

### useLocalStorage from VueUse

The VueUse composable [useLocalStorage](https://vueuse.org/core/uselocalstorage/#uselocalstorage) provides a much simpler approach to persisting values in our store with much less code. useLocalstorage will check our local storage for store values and will also smartly handle serialization for us based on the data type of provided default value.

To get started, install the VueUse library:

```jsx
yarn add @vueuse/core

# or with npm
npm i @vueuse/core
```

Now we can import useLocalStorage into our code and get persistence in just one line of code.

Update your counter store to include the following code:

📁 **src/stores/counter.js**

```jsx
import { useLocalStorage } from "@vueuse/core"

state: () => {
    return {
     count: useLocalStorage('count', 0), _//useLocalStorage takes in a key of 'count' and default value of 0_
    };
  },
```

### Using a plugin

The final approach we’re going to look at is using a plugin. A great example is the Pinia plugin called [persistedstate](https://github.com/prazdevs/pinia-plugin-persistedstate). This is a tiny package that is highly customizable, compatible with both Vue 2 and Vue 3, and (at the time of this writing) is being actively maintained.

To use this, we have to install it:

```jsx
yarn add pinia-plugin-persistedstate

# or with npm
npm i pinia-plugin-persistedstate
```

Update your main.js file to use the plugin:

📁 **src/main.js**

```jsx
...

import piniaPluginPersistedState from "pinia-plugin-persistedstate"

const pinia = createPinia();

pinia.use(piniaPluginPersistedState)
```

Finally, add a property called persist and set it to true in your counter store object.

📁 **src/stores/counter.js**

```jsx
export const useCounterStore = defineStore("counter", {
  state: () => {
    return {
     count: 0,
    };
  },
  ...
  persist: true,
});
```

You can also configure how a store is persisted by specifying options to the persist property. For example, our plugin persists data in local storage by default but we can modify it to use session storage by updating the storage configuration that exists in the persist property:

```jsx
export const useCounterStore = defineStore("counter", {
  state: () => {
    return {
     count: 0,
    };
  },
  ...
  persist: {
    storage: sessionStorage, _// data in sessionStorage is cleared when the page session ends._
  },
});
```

All the available configuration options are explained [here](https://prazdevs.github.io/pinia-plugin-persistedstate/guide/config.html).

### Where to go from here

Although we used a very simple example to demonstrate how to persist state in Pinia, the same approach would apply when working with more complex stores.

Please keep in mind that data stored in localStorage is **not private** and you should be careful with storing sensitive information there.

If you’re curious about Pinia, you should check out our [Pinia Fundamentals course](https://www.vuemastery.com/courses/pinia-fundamentals/fundamentals-what-is-pinia/) taught by Sandra Rogers.

_Originally published at_ [_https://www.vuemastery.com_](https://www.vuemastery.com/blog/refresh-proof-your-pinia-stores/) _on October 31, 2022._

* * *