Gerenciamento de estados¶
Conceitos de gerenciamento de estados¶
O gerenciamento de estados é uma parte importante do desenvolvimento de aplicações web. Ele é responsável por manter o estado da aplicação sincronizado com a interface de usuário, garantindo que as informações exibidas na tela estejam sempre atualizadas.
No Vue.js, o gerenciamento de estados é feito por meio de variáveis reativas, que são propriedades da instância Vue que podem ser monitoradas e reagir a mudanças. Quando uma variável reativa é alterada, o Vue.js automaticamente atualiza a interface de usuário para refletir essa mudança.
No entanto, vamos considerar a aplicação de exemplo que fizemos na aula anterior, para listagem e exclusão de produtos. Nessa aplicação, a listagem de produtos é feita por meio de um componente ProductList, que recebe um array de produtos como propriedade e emite um evento quando o usuário clica em um ícone de lixeira para excluir um produto.
Contudo, considere que o usuário clique no ícone de lixeira para excluir um produto. Nesse caso, o componente ProductList emite um evento para o componente pai, que é responsável por remover o produto da lista. A remoção do produto é refletida na interface de usuário, pois a variável reativa que armazena a lista de produtos é atualizada.
Porém se o usuário clicar para ver os detalhes de um produto e depois retornar para a listagem de produtos, a lista de produtos será recarregada para o estado inicial, ou seja, as alterações ou exclusões de produto são perdidas. Isso ocorre porque a lista de produtos é uma variável local do componente e não é compartilhada com outros componentes.
E esse comportamento pode ser um problema em aplicações maiores, onde vários componentes precisam compartilhar o mesmo estado. Para resolver esse problema, o Vue.js fornece uma solução chamada Pinia, que é uma biblioteca de gerenciamento de estados com uma interface simples e intuitiva.
Pinia¶
Pinia é uma biblioteca de gerenciamento de estados para Vue.js que fornece uma maneira simples e intuitiva de compartilhar estados entre componentes.
Com Pinia, é possível criar um store global que armazena o estado da aplicação e compartilhá-lo com todos os componentes que precisam acessar ou modificar esse estado. Dessa forma, é possível manter o estado da aplicação sincronizado entre os diferentes componentes, garantindo que as informações exibidas na tela estejam sempre atualizadas.
Nas próximas aulas, vamos aprender a criar um store global com Pinia e utilizá-lo para gerenciar o estado da aplicação. Vamos ver como definir o estado da aplicação, como acessar e modificar esse estado a partir dos componentes e como reagir a mudanças no estado para atualizar a interface de usuário.
Também, partiremos da aplicação de exemplo que fizemos na aula anterior, quando estudamos os conceitos do vue-router. A aplicação em questão faz a listagem e exclusão de produtos, e vamos refatorá-la para utilizar Pinia. Vamos ver como criar um store global para armazenar a lista de produtos e como compartilhar esse estado entre os diferentes componentes da aplicação.
Instalação do Pinia¶
Como no caso do VueRouter, o Pinia é uma biblioteca externa que precisa ser instalada no projeto. Para isso, você pode escolher incluí-la no momento da criação do projeto ou instalá-la posteriormente. Para instalar o Pinia em um projeto existente, você pode usar o seguinte comando:
Em seguida, você precisa configurar o Pinia no seu projeto Vue.js. Para isso, abra o arquivo src/main.js e adicione o seguinte código:
A versão completa do arquivo src/main.js ficará assim:

Versão completa
Com isso, o Pinia estará configurado e pronto para ser utilizado no seu projeto Vue.js. Agora, você pode começar a criar stores e gerenciar o estado da sua aplicação de forma eficiente.
Criando um store com Pinia¶
Para criar um store com Pinia, você precisa definir um arquivo que exporta uma função que cria o store. Essa função deve retornar um objeto que contém o estado, as ações e os getters do store.
Vamos criar um store para gerenciar o carrinho e a sua visualização. Crie um arquivo chamado cart.js dentro da pasta src/stores e adicione o seguinte código:
import { ref } from 'vue';
import { defineStore } from 'pinia';
export const useCartStore = defineStore('cart', () => {
const showCart = ref(false);
const cart = ref({
items: [],
total: 0,
});
function decrementBookToCart(book) {
const existingBook = cart.value.items.find((item) => item.id === book.id);
if (existingBook.quantity === 1) {
cart.value.items = cart.value.items.filter((item) => item.id !== book.id);
} else {
existingBook.quantity--;
}
cart.value.total -= book.price;
}
function incrementBookToCart(book) {
const existingBook = cart.value.items.find((item) => item.id === book.id);
existingBook.quantity++;
cart.value.total += book.price;
}
function addToCart(book) {
const existingBook = cart.value.items.find((item) => item.id === book.id);
if (existingBook) {
existingBook.quantity++;
} else {
cart.value.items.push({ ...book, quantity: 1 });
}
cart.value.total += book.price;
alert(`Adicionado ${book.title} ao carrinho!`);
}
return {
showCart,
cart,
incrementBookToCart,
decrementBookToCart,
addToCart,
};
});
Nesse caso, estamos criando um store chamado cart que contém duas variáveis reativas: showCart e cart. A função defineStore é usada para definir o store e o nome do store é passado como primeiro argumento.
Também, definimos três funções: incrementBookToCart, decrementBookToCart e addToCart. Essas funções são responsáveis por manipular o estado do carrinho, adicionando ou removendo livros e atualizando o total do carrinho. Note que essas funções já estavam desenvolvidas anteriormente, mas agora estão encapsuladas dentro do store.
Utilizando o store no componente¶
Agora que temos o store criado, podemos utilizá-lo nos nossos componentes. Para isso, vamos importar o store e usar a função useCartStore para acessar o estado do carrinho.
Primeiramente, vamos ajustar o componente HeaderComponent.vue para usar o store do carrinho. Abra o arquivo src/components/HeaderComponent.vue e modifique o bloco <script setup> para incluir o uso do store:
<script setup>
import { useCartStore } from '@/stores/cart';
const cartStore = useCartStore();
</script>
Agora, para exibir o carrinho, vamos usar a variável showCart do store. No bloco <template>, modifique o código para usar cartStore.showCart:
| ./src/components/HeaderComponent.vue | |
|---|---|
Note que alteramos o evento de clique para alternar o valor de showCart diretamente do store. Isso garante que o estado do carrinho seja compartilhado entre os componentes. Dessa forma, a função de emit que antes era usada para emitir o evento click-cart não é mais necessária, pois estamos manipulando o estado diretamente do store.

Versão completa
| ./src/components/HeaderComponent.vue | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | |
Definindo uma store para os livros.¶
Agora, vamos criar um store para gerenciar os livros. Crie um arquivo chamado books.js dentro da pasta src/stores e adicione o seguinte código:
Note que, como no caso do store do carrinho, estamos usando a função defineStore para definir o store dos livros. O estado do store é uma variável reativa chamada books, que contém um array de objetos representando os livros disponíveis. Também, essas informações já estavam definidas anteriormente, mas agora estão encapsuladas dentro do store.
Utilizando o store dos livros no componente HomeView¶
Agora, vamos editar o arquivo src/views/HomeView.vue para utilizar o store do carrinho. Abra o arquivo e deixe o seu conteúdo como abaixo (as novas linhas adicionadas estão destacadas):
Temos, agora, importado os stores useBooksStore e useCartStore, e instanciado as variáveis booksStore e cartStore. Essas variáveis nos permitem acessar o estado dos livros e do carrinho, respectivamente. Além disso, o componente CartComponent agora recebe o estado do carrinho diretamente do store, e o componente BooksListing recebe a lista de livros do store dos livros.
Fazendo a barra de pesquisa¶
Agora, vamos fazer a barra de pesquisa para filtrar os livros. Para isso, vamos adicionar uma variável reativa chamada filterText no store dos livros e criar um método para filtrar os livros com base nessa consulta.
Também vai precisar de uma função computada para retornar os livros filtrados com base na consulta de pesquisa. A função computada terá a seguinte estrutura:
| ./src/stores/books.js | |
|---|---|
Também, será necessário retornar a variável filterText e a função computada filteredBooks do store. Assim, o componente BooksListing poderá usar a lista filtrada de livros.
A versão completa do arquivo src/stores/books.js ficará assim (as linhas novas estão destacadas):

Versão completa
Agora, vamos ajustar o componente HomeView.vue para usar a lista filtrada de livros. Abra o arquivo src/views/HomeView.vue e modifique o bloco <template>, alterando a variável books para filteredBooks (Veja a linha destacada):
Por fim, vamos ajustar o componente HeaderComponent.vue para atualizar o valor de filterText no store dos livros quando o usuário digitar na barra de pesquisa. Abra o arquivo src/components/HeaderComponent.vue e modifique o bloco <script setup> para incluir o uso do store dos livros:
| src/components/HeaderComponent.vue | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | |
Agora, quando o usuário digitar na barra de pesquisa, o valor de filterText no store dos livros será atualizado automaticamente, e a lista de livros exibida no componente BooksListing será filtrada com base nesse valor.