Persist data with Vue Pinia
Tags: vue, pinia, javascript
Published: 2024-03-15 14:30:00

---
title: Persist data with Vue Pinia
published: true
description: 
tags: vuejs, pinia, javascript
cover_image: https://pinia.vuejs.org/social.png
# Use a ratio of 100:42 for best results.
published_at: 2024-03-15 14:30 +0000
---
## Introduction
As a Software Developer who spends more time on the Backend, every now and then I try to do some things on the frontend occassionally. I wanted to explore [Pinia](https://pinia.vuejs.org/) and experience some of its features. In this post, I will share how I persisted data using Pinia and localStorage.

## The App
To create the Vue 3 app, we run the command below and follow the prompt. Be sure to add Pinia for state management.

`npm create vue@latest`

You can run the commands to install dependencies and start the app.

`cd project-name`
`npm install`
`npm run dev`

Open the App with an editor(I use Vscode).

Create a file named authStore.js inside the src/stores folder. Add this code to the file.

```js
import { defineStore } from "pinia";
import { ref, computed } from "vue";

export const useAuthStore = defineStore("auth", () => {
  const user = ref(null);

  const getUser = computed(() => user.value);

  const setUser = (newUser) => {
    user.value = newUser;
  };

  return {
    user,
    setUser,
    getUser,
  };
});

```
We can now use the store values in our views. I had to clean up the default codes in the view files.

**src/App.vue**
```js
<script setup>
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from './components/HelloWorld.vue'
</script>

<template>
  <header>
    <nav>
      <RouterLink to="/">Home</RouterLink>
      <RouterLink to="/about">About</RouterLink>
    </nav>
  </header>

  <RouterView />
</template>

<style scoped>
</style>
```

**src/Home.vue**
```js
<script setup>
import { ref } from 'vue';
import { useAuthStore } from '@/stores/authStore';

const authStore = useAuthStore();
const name = ref(null);

const login = () => {
  authStore.setUser(name.value);
};
</script>

<template>
  <main>
    <h1>Home</h1>
    <p v-if="authStore.user !== null">Welcome, {{ authStore.getUser }}</p>
    <div>
      <h3>Enter your name</h3>
      <form @submit.prevent="login">
        <input type="text" v-model="name">
        <button type="submit">Login</button>
      </form>
    </div>
  </main>
</template>
```

**src/About.vue**
```js
<script setup>
import { useAuthStore } from '@/stores/authStore';

const authStore = useAuthStore();
</script>
<template>
  <div class="about">
    <h1>This is an about page</h1>
    <p v-if="authStore.user !== null">Welcome, {{ authStore.getUser }}</p>
  </div>
</template>

<style>
</style>

```
In the App.vue, I removed all the unnecessary codes. In the home and about, I mimicked a login and the user value was saved to the store. So, in a real login system we can have data from API and save it to the store and use across pages.

## The Issue
If you notice, when the page is refreshed, the user value in the store resets to null. This is because Pinia stores are not persisted across refreshes.

## The fix
There are different ways to fix this particular issue. I will use localstorage to solve this in the store. We have to make a few changes.

Update the login method in Home.vue. This stores the value in the localstorage.

```js
const login = () => {
  authStore.setUser(name.value);
  localStorage.setItem('app_user', name.value);
};
```

Update the authStore to load value from localstorage if the value exists.
```js
import { defineStore } from "pinia";
import { ref, computed } from "vue";

export const useAuthStore = defineStore("auth", () => {
  const user = ref(null);

  if (localStorage.getItem("app_user")) {
    user.value = localStorage.getItem("app_user");
  }

  const getUser = computed(() => user.value);

  const setUser = (name) => {
    user.value = name;
  };

  return {
    user,
    setUser,
    getUser,
  };
});
```

With these changes, even with page reload, the data persists! Be sure to drop comments, questions or suggestions.