Pinia

How to use Vue with Pinia - free starter

This article will teach you how to integrate Pinia State Management Tool with your project. You can start managing your application's state more efficiently with Pinia features and Bootstrap 5.

Lets see how to use Pinia with MDB 5 across our layout, components, and utilities.

Since Vuex is now in maintenance mode, the recommended state management library is Pinia. Pinia provides a simple API and has solid type inference so you can use it with TypeScript.

Live preview

Prerequisites

Before starting the project make sure to install the following utilities:


Creating a new project

First, we need to create a new Vite project.

Step 1

Init the project and choose vue framework. You can add a name for your project as we did in example below

        
            
          npm init vite@latest my-vue-app
    
        
    

Step 2

Navigate to app's directory.

        
            
        cd my-vue-app
    
        
    

Step 3

Install dependencies.

        
            
        npm install
    
        
    

Step 4

Setup MDB.

        
            
    npm install mdb-vue-ui-kit
    
        
    

Step 5

Import CSS. Add the following line at the beginning of your main.ts file:

        
            
        import 'mdb-vue-ui-kit/css/mdb.min.css';
    
        
    

Step 6

Import Font Awesome and Roboto font. Add the following lines in public/index.html file inside head section:

        
            
        <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet" />
        <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900&display=swap" rel="stylesheet" />
    
        
    

Step 7

Enable sourcemaps during development.

        
            
        export default defineConfig({
          plugins: [vue()],
          css: {
            devSourcemap: true,
          },
        });
    
        
    

Step 8

Launch the application.

        
            
        npm run dev
    
        
    

Installation

Before we install Pinia, we have to create routing for our application.

Step 1

Since we are using vue 3, let's install vue router 4.

        
            
        npm install vue-router@4
    
        
    

Step 2

Create router folder inside src directory and put index.ts inside. The app will have 3 views, so we have to create 3 routes.

        
            
    import { createRouter, createWebHashHistory } from "vue-router";

    const routes = [
      {
        path: "/",
        component: () => import("../views/CarouselView1.vue"),
      },
      {
        path: "/view2",
        component: () => import("../views/CarouselView2.vue"),
      },
      {
        path: "/view3",
        component: () => import("../views/CarouselView3.vue"),
      },
    ];
    
    export default createRouter({
      history: createWebHashHistory(),
      routes,
    });
    
        
    

Step 3

Create a new views directory with CarouselView1.vue, CarouselView2.vue and CarouselView3.vue inside. For now, add a template for each view with name of the file inside, so we will be able to check if the content is changing.

Step 4

Next thing to do is to register our router inside main.ts file.

        
            
    import { createApp } from "vue";
    import App from "./App.vue";
    import "mdb-vue-ui-kit/css/mdb.min.css";
    import router from "./router/index";
    
    createApp(App).use(router).mount("#app");
    
    
        
    

Step 5

Now we can add them to App.vue and check if everything is working properly. Let's put it inside a MDBNavbar component to make everything look nice.

        
            
    <template>
      <MDBNavbar light bg="light" container class="flex-start">
        <MDBNavbarBrand href="#">
          <img
            src="https://mdbootstrap.com/img/logo/mdb-transaprent-noshadows.webp"
            height="30"
            alt=""
            loading="lazy"
          />
        </MDBNavbarBrand>
        <MDBNavbarNav class="flex-row">
          <MDBNavbarItem to="/" class="me-3">view1</MDBNavbarItem>
          <MDBNavbarItem to="/view2" class="me-3">view2</MDBNavbarItem>
          <MDBNavbarItem to="/view3">view3</MDBNavbarItem>
        </MDBNavbarNav>
      </MDBNavbar>
      <MDBContainer class="mt-5">
        <router-view />
      </MDBContainer>
    </template>
    
        
    
        
            
    <script setup lang="ts">
      import {
        MDBNavbar,
        MDBNavbarBrand,
        MDBNavbarNav,
        MDBNavbarItem,
        MDBContainer,
      } from "mdb-vue-ui-kit";
    </script>
    
        
    

When you click on an item in the menu, you should see the content of our app changing.

Step 6

If everything works fine, we can finally install pinia

        
            
        npm install pinia   
    
        
    

Step 7

We need to create a new store. Create a new directory called stores and carouselStore.ts inside it.

        
            
    import { defineStore } from "pinia";
    
    export const useCarouselStore = defineStore({
      id: "carousel",
    });
    
    
        
    

Step 8

Register the store inside main.ts

        
            
    import { createApp } from "vue";
    import App from "./App.vue";
    import "mdb-vue-ui-kit/css/mdb.min.css";
    import router from "./router/index";
    import { createPinia } from "pinia";

    createApp(App).use(router).use(createPinia()).mount("#app");
    
        
    

Adding new content

After we go through all the previous steps, we can start developing our application. We are going to use MDBCarousel component with buttons that will increase a counter value.

Before that, lets delete style.css and HelloWorld.vue files. We are not going to use them.

Step 1

First, let's create some data for the carousel component. Create a carouselData.ts file inside stores directory.

        
            
    export default [
      {
        src: "https://mdbootstrap.com/img/Photos/Slides/img%20(1).webp",
        alt: "...",
        label: "First slide label",
        caption: "Nulla vitae elit libero, a pharetra augue mollis interdum.",
      },
      {
        src: "https://mdbootstrap.com/img/Photos/Slides/img%20(2).webp",
        alt: "...",
        label: "Second slide label",
        caption: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
      },
      {
        src: "https://mdbootstrap.com/img/Photos/Slides/img%20(3).webp",
        alt: "...",
        label: "Third slide label",
        caption: "Praesent commodo cursus magna, vel scelerisque nisl consectetur.",
      },
      {
        src: "https://mdbootstrap.com/img/Photos/Slides/img%20(4).webp",
        alt: "...",
        label: "Fourth slide label",
        caption: "Nulla vitae elit libero, a pharetra augue mollis interdum.",
      },
      {
        src: "https://mdbootstrap.com/img/Photos/Slides/img%20(5).webp",
        alt: "...",
        label: "Fifth slide label",
        caption: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
      },
      {
        src: "https://mdbootstrap.com/img/Photos/Slides/img%20(6).webp",
        alt: "...",
        label: "Sixth slide label",
        caption: "Praesent commodo cursus magna, vel scelerisque nisl consectetur.",
      },
      {
        src: "https://mdbootstrap.com/img/Photos/Slides/img%20(7).webp",
        alt: "...",
        label: "Seventh slide label",
        caption: "Nulla vitae elit libero, a pharetra augue mollis interdum.",
      },
      {
        src: "https://mdbootstrap.com/img/Photos/Slides/img%20(8).webp",
        alt: "...",
        label: "Eighth slide label",
        caption: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
      },
      {
        src: "https://mdbootstrap.com/img/Photos/Slides/img%20(9).webp",
        alt: "...",
        label: "Nineth slide label",
        caption: "Praesent commodo cursus magna, vel scelerisque nisl consectetur.",
      },
      {
        src: "https://mdbootstrap.com/img/Photos/Slides/img%20(10).webp",
        alt: "...",
        label: "Tenth slide label",
        caption: "Nulla vitae elit libero, a pharetra augue mollis interdum.",
      },
      {
        src: "https://mdbootstrap.com/img/Photos/Slides/img%20(11).webp",
        alt: "...",
        label: "Eleventh slide label",
        caption: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
      },
      {
        src: "https://mdbootstrap.com/img/Photos/Slides/img%20(12).webp",
        alt: "...",
        label: "twelfth slide label",
        caption: "Praesent commodo cursus magna, vel scelerisque nisl consectetur.",
      },
    ];
    
        
    

Step 2

Modify the store file. We are going to add a simple state with 3 values that we are going to read or change and 1 action to increment the counter value by 1. Note that we are importing carousel data here, so we won't have to do the same in every component. This will allow us to modify the data we pass to the carousel. You can try this yourself after completing this tutorial.

        
            
    import { defineStore } from "pinia";
    import carouselData from "./carouselData";
    
    export const useCarouselStore = defineStore({
      id: "carousel",
      state: () => ({
        carousel: 0,
        carouselData,
        counter: 0,
      }),
      actions: {
        increaseCount() {
          this.counter++;
        },
      },
    });
    
    
        
    

Step 3

Let's use the data and fill the views with content. To use the store all we have to do is to import it and invoke. Now we have access to our state, actions, getters and more.

CarouselView1.vue

        
            
    <template>
      <div class="text-center">
        <MDBBtn
          rounded
          color="primary"
          class="mb-3"
          @click="carouselStore.increaseCount"
          >Increase counter from View 1</MDBBtn
        >
      </div>
      <div class="position-relative">
        <h2
          class="text-center position-absolute left-0 top-0 ms-3 mt-3 text-white"
          style="z-index: 10"
        >
          view 1 - item id <span>{{ carouselStore.carousel }}</span> - counter
          <span>{{ carouselStore.counter }}</span>
        </h2>
        <MDBCarousel
          v-model="carouselStore.carousel"
          :items="carouselStore.carouselData"
          fade
        />
      </div>
    </template>
    
        
    
        
            
    <script setup lang="ts">
      import { MDBCarousel, MDBBtn } from "mdb-vue-ui-kit";
      import { useCarouselStore } from "../stores/carouselStore";
      const carouselStore = useCarouselStore();
    </script>
    
        
    

CarouselView2.vue

        
            
    <template>
      <div class="text-center">
        <MDBBtn
          rounded
          color="primary"
          class="mb-3"
          @click="carouselStore.increaseCount"
          >Increase counter from View 2</MDBBtn
        >
      </div>
      <div class="position-relative">
        <h2
          class="text-center position-absolute left-0 top-0 ms-3 mt-3 text-white"
          style="z-index: 10"
        >
          view 2 - item id <span>{{ carouselStore.carousel }}</span> - counter
          <span>{{ carouselStore.counter }}</span>
        </h2>
        <MDBCarousel
          v-model="carouselStore.carousel"
          :items="carouselStore.carouselData"
          fade
        />
      </div>
    </template>
    
        
    
        
            
    <script setup lang="ts">
      import { MDBCarousel, MDBBtn } from "mdb-vue-ui-kit";
      import { useCarouselStore } from "../stores/carouselStore";
      const carouselStore = useCarouselStore();
    </script>
    
        
    

CarouselView3.vue

        
            
    <template>
      <div class="text-center">
        <MDBBtn
          rounded
          color="primary"
          class="mb-3"
          @click="carouselStore.increaseCount"
          >Increase counter from View 3</MDBBtn
        >
      </div>
      <div class="position-relative">
        <h2
          class="text-center position-absolute left-0 top-0 ms-3 mt-3 text-white"
          style="z-index: 10"
        >
          view 3 - item id <span>{{ carouselStore.carousel }}</span> - counter
          <span>{{ carouselStore.counter }}</span>
        </h2>
        <MDBCarousel
          v-model="carouselStore.carousel"
          :items="carouselStore.carouselData"
          fade
        />
      </div>
    </template>
    
        
    
        
            
    <script setup lang="ts">
      import { MDBCarousel, MDBBtn } from "mdb-vue-ui-kit";
      import { useCarouselStore } from "../stores/carouselStore";
      const carouselStore = useCarouselStore();
    </script>
    
        
    

Everything should work fine and after the route changes you can see the carousel is still on the same element. You can increase the counter on button click. The counter will keep that value and display it on other routes aswell.


More about pinia

For more information, see pinia documentation page. There you can read about other options, server-side rendering, multiple states and others.


Frontend features

MDB UI KIT:

To create the project we used mdb ui kit, with which we can build basic views very quickly.

Views and Layouts:

In this project we are using routing to change the view of the application. Thanks to that we can see the changes we are making after implementing pinia to our app.