Trying Pinia for Shared State in a Vue App

Published:

When building a Vue front-end project, there are always situations where data needs to be shared across components. In a single-page application, if you need something that behaves like a global variable, Pinia is a simple and efficient choice.

Installing Pinia

Pinia can be installed with the package manager you normally use:

# 使用pnpm
pnpm i pinia

#或者使用 rarn
yarn add pinia

# 或者使用 npm
npm install pinia

Registering Pinia in main.js

After installation, import Pinia at the application entry point and register it before mounting the Vue app:

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { createPinia } from 'pinia'
import router from "./router/index.js";

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


app.use(pinia)
app.use(router)
app.mount('#app')

Here, createPinia() creates the Pinia instance, and app.use(pinia) makes it available throughout the project. The router is also registered in the same entry file.

Creating a Store

Create a stores directory under the project’s src folder, then add an index.js file inside it:

import { defineStore } from "pinia"

export const useTestStore = defineStore("Test",{
    state:()=>({
        count:0
    }),
    getters:{
        double:(state)=>state.count * 2,
    },
    actions : {
        add(){
            this.count ++
        },
    },
})

This store defines a state, which can be understood as a global variable inside the project. The getters section works similarly to computed properties in Vue, while actions can be thought of as methods in a component.

In this example, count starts from 0, double returns twice the current count, and add() increases count by one.

Using the Store Across Pages

Assume the project has two pages. The router configuration in router/index.js looks like this:

import { createRouter,createWebHashHistory } from 'Vue-router'
import HomeView from "../views/HomeView.vue";
import TestView from "../views/TestView.vue";

const router = createRouter({
    history:createWebHashHistory(),
    routes:[
        {
            path:'/',
            name : 'home',
            component:HomeView
        },
        {
            path : '/test',
            name : 'test',
            component:TestView
        }
    ]

})

export default router;

From this routing setup, you can see the page components used in the project: HomeView.vue and TestView.vue.

The store can then be used inside these components:

<template>
<h1>Home Page</h1>
<div class="card">
    <button type="button" @click="store.add">count is {{ store }}</button>
</div>
</template>

<script setup>
import {useTestStore} from "../stores/index.js";

const store = useTestStore()
</script>

With <script setup>, importing and calling useTestStore() gives the component access to the shared store. The button triggers store.add, and the template displays the current store value.

Running and Checking the Result

Start the development server with npm run dev. Navigate to the home page through the route, then click the button to trigger the event that increases count. You can observe the store value changing in the button.

When switching to the test page, the store value is not reset to its initial state. Instead, it keeps the value that was already increased on the home page. If you click the button on the test page, the same store value continues to increase. After switching back to the home page, the value still remains unchanged.

This shows that the store can share variables across components and achieves the effect of a global variable in the application.

A Simple but Useful State Management Choice

Pinia is straightforward to use, but it is also powerful enough for common shared-state needs in Vue projects. When defining different global states, you can create separate files to keep them organized. With this structure, sharing variables globally in Vue no longer needs to be a headache.