Integrate Pinia

In this section, we will continue on using the project on Build with Options API section.

Getting started

Installation

npm install pinia@next

Create pinia store

// import { createApp } from 'vue';
// import App from './App.vue';
import { createPinia } from 'pinia';

// const app = createApp(App);
app.use(createPinia()); 

// app.mount('#app');

Define useTodo store

Create useTodo.js in src/stores

└─ src
    └─ stores
        └─ useTodo.js
    ├─ App.vue
    └─ main.js

After creating useTodo.js, let's define the store.

// src/stores/useTodo.js
import { defineStore } from 'pinia';

export const useTodo = defineStore('todo', {
    state() {
        return {
            // ...
        }
    },
    getters: {},
    actions: {}
})

Moved all options to store

import { defineStore } from 'pinia';

export const useTodo = defineStore('todo', {
    state() {
        return {
            todoInput: '',
            filterTodo: 'All',
            todos: [
                { id: 1, item: 'Learn Pinia', completed: false },
                { id: 2, item: 'Learn Options API', completed: false },
                { id: 3, item: 'Learn Vue 3', completed: false },
            ]
        }
    },
    getters: {
        filteredTodos() {
            const completedTodos = this.todos.filter(todo => todo.completed)
            const incompleteTodos = this.todos.filter(todo => !todo.completed)

            if (this.filterTodo === 'All') return this.todos;
            if (this.filterTodo === 'Completed') return completedTodos;
            if (this.filterTodo === 'Incomplete') return incompleteTodos;
        }
    },
    actions: {
        addTodo() {
            let newTodo = {
                id: this.todos[this.todos.length - 1].id + 1,
                item: this.todoInput,
                completed: false
            }

            this.todos.push(newTodo)

            this.todoInput = ''
        },
        deleteTodo(id) {
            this.todos = this.todos.filter(todo => todo.id !== id)
        },
        completeTodo(id) {
            const todo = this.todos.find(todo => todo.id === id)
            todo.completed = !todo.completed
        }
    }
})

Isn't it easy! 😄 This is the reason why I like using Pinia.

Use useTodo store

Let's import and initialize our store instance:

<script>
import { useTodo } from './stores/useTodo';

export default {
    name: 'TodoApp',
    setup() {
        const store = useTodo();

        return {
            store
        }
    }
}
</script>

Next, let's attach store to each state, getters, and actions we used in the <template>.

<template>
    <h1>Todo App</h1>

    <form>
        ...
        <input v-model="store.todoInput" type="text">

        <button @click.prevent="store.addTodo()">Add Todo</button>

        <select v-model="store.filterTodo" name="filterTodos" id="filterTodos">
            ...
        </select>
    </form>

    <ul>
        <li :key="todo.id" v-for="todo in store.filteredTodos">
            ...
            <button @click.prevent="store.completeTodo(todo.id)">{{ todo.completed ? 'Undo' : 'Complete' }}</button>
            <button @click.prevent="store.deleteTodo(todo.id)">Delete</button>
        </li>
    </ul>
</template>

Nice work! Integrating pinia to our project is as simple as 1 + 1. 😄