Как использовать Pinia в Vue 3
Управление состоянием — одно из требований при создании современного веб-сайта Vue 3. Такие функции, как аутентификация, элементы корзины, светлый/темный режим, должны быть доступны двум или более компонентам на веб-сайте vue, следовательно, необходимо управление состоянием. Цель этой статьи — помочь вам использовать Pinia для управления состоянием на современном веб-сайте Vue 3.
Что такое Pinia?
Pinia — это библиотека управления состоянием, предоставленная создателем vue для эффективного управления состоянием без шаблонного кода. Он предоставляет вам универсальное хранилище для доступа к состоянию и его изменения из любого компонента вашей кодовой базы.
Предварительные условия
Для работы с этим руководством необходимы базовые знания Javascript и API композиции vue3. И, конечно же, редактор кода (желательно Visual Studio Code).
Настройка Vue3 с помощью Pinia
Прежде всего откройте интерфейс командной строки, перейдите в предпочитаемый каталог папки и введите команду npm create vue@latest.
Это поможет вам создать кодовую базу vue с предпочитаемыми вами конфигурациями, выбрав «да» или «нет» при появлении подсказки. Назовите свой проект и нажмите Enter. В этой статье мы собираемся нажимать «Нет» на каждый вопрос, за исключением вопроса, показанного для добавления Pinia и vue router.
После всех настроек введите следующие команды, чтобы запустить проект.
cd your-project-name npm install npm run dev
Вы должны увидеть страницу, подобную приведенной ниже, на localhost:5173
Работа с Pinia
Шаг 1 (Создание Store)
Store — это место или контейнер, в котором хранится наше состояние. Доступ к этому хранилищу (или сторам) можно получить из любого места вашей кодовой базы (до этого мы еще доберемся).
Выполнив первоначальную настройку vue, удалите все шаблонные коды и файлы в папке компонентов и хранилища. Чтобы упростить задачу, мы собираемся создать простой веб-сайт без стиля, который отображает список товаров на одной странице и корзину, в которой хранятся товары, которые понравились пользователю, как на веб-сайте электронной коммерции.
Теперь внутри папки stores создайте файл с именем cart.js. Этот файл будет содержать и хранить объекты, которые пользователь добавляет в массив состояний (cartItems). В этом файле импортируйте defineStore из Pinia и ref из vue.
import { ref, computed} from 'vue' import { defineStore} from 'pinia'
Это хранилище определений, которое мы только что импортировали, как следует из его названия, используется для определения или создания экземпляра хранилища. Этот метод сообщает vue и всей вашей кодовой базе, что функция, к которой он подключен, является хранилищем. Чтобы увидеть defineStore в действии, создайте и экспортируйте переменную (const) и присвойте ей defineStore.
export const = defineStore()
Но прежде чем дать имя этой только что созданной переменной, вам нужно кое-что знать о предпочтительном соглашении Pinia об именах store:
- Имя переменной хранилища должно начинаться с use
- Тогда имя хранилища должно следовать за использованием, т. е. именем файла, в котором вы создаете хранилище (в нашем случае store).
- Наконец, имя должно заканчиваться на store.
Следуя приведенному выше соглашению об именах, имя нашей функции store будет называться useCartStore.
export const useCartStore = defineStore();
Важно знать, что defineStore принимает два аргумента:
- Название store (строка)
- Стрелочная функция
В качестве названия нашего store мы выберем cart (корзину).
export const useCartStore = defineStore("cart", () => {});
Помимо прочего, стрелочная функция должна возвращать объект. Этот объект будет содержать все, что вы создадите внутри функции стрелки.
export const useCartStore = defineStore("cart", () => { return {}; });
Шаг 2 (State, getters, actions)
State, getters и actions — это то, что находится внутри хранилища. Давайте узнаем, что они собой представляют.
State: это именованная константа, которой присвоен ref. Ссылка может быть строкой, массивом, объектом, логическим значением или нулевым значением. Обычно в каждом store есть только один. Если хранилище имеет более одного состояния, создайте для него другое хранилище.
Getters: это именованные константы, которые вычислены присвоены им. Они используются, когда вы хотите изменить исходное значение состояния перед доступом к нему.
Actions: это именованные функции, которые используются для изменения свойства состояния или выполнения действия через состояние или с его помощью.
Чтобы создать состояние, перейдите к стрелочной функции внутри defineStore и создайте константу. Назначьте метод ref созданной константе. В нашем случае нам нужен массив для хранения объектов.
Мы назовем этот массив carsItems. После создания состояния обязательно включите его в возвращаемый объект, чтобы к нему можно было получить глобальный доступ.
export const useCartStore = defineStore("cart", () => { const cartItems = ref([]); return { cartItems }; });
Давайте создадим геттер, который сортирует наш массив в порядке их добавления. Помните, для этого используется ключевое слово Computed:
export const useCartStore = defineStore("cart", () => { const cartItems = ref([]); //getter const sortItems = computed(() => [...cartItems.value].sort((a, b) => b.id - a.id) ); return { cartItems, sortItems }; });
Наконец, давайте создадим два действия; один для добавления объекта в состояние carsItems с помощью метода push, другой для удаления элемента, добавленного из состояния carsItems, с помощью метода фильтра.
export const useCartStore = defineStore("cart", () => { const cartItems = ref([]); //getter const sortItems = computed(() => [...cartItems.value].sort((a, b) => b.id - a.id) ); //actions const addItems = (item) => { //Find the object whose id is similar to the item const checkItems = cartItems.value.find((x) => x.id === item.id); if (!checkItems) { cartItems.value.push(item); } }; const removeItems = (id) => { cartItems.value = cartItems.value.filter((x) => x.id !== id); }; return { cartItems, sortedItems, addItems, removeItems }; });
Обратите внимание, что мы немного изменили действие addItems; он проверит, был ли добавлен объект, чтобы избежать его повторного добавления.
Шаг 3 (Интерфейс веб-сайта)
Это руководство будет неполным без пользовательского интерфейса для проверки нашего состояния и модификаторов. Итак, мы создадим две страницы с простым пользовательским интерфейсом и массивом из 10 объектов. В папке представлений создайте новый файл с именем CartView.vue.
Нажмите HomeView и создайте массив ссылок из 10 объектов. Сопоставьте эти объекты и отобразите их с помощью кнопки, каждая из которых имеет базовый стиль.
<script setup> import { ref } from 'vue'; const newItems = ref([ { title: 'HP Laptop', id: 1 }, { title: 'Iphone X', id: 2 }, { title: 'Travelling Bag', id: 3 }, { title: 'Nike Shoes', id: 4 }, { title: 'Leather Belts', id: 5 }, { title: 'Mechanical Keyboard', id: 6 }, { title: 'Water Gun', id: 7 }, { title: 'Earth Globe', id: 8 }, { title: 'Javascript book', id: 9 }, { title: 'Black T-shirt', id: 10 }, ]) </script> <template> <main> <h1>Items for sale</h1> <div v-for="item in newItems" :key="item.id"> <div class="item"> <h1> </h1> <button>Add</button> </div> </div> </main> </template> <style> .item { width: 50em; height: auto; margin: 10px auto; border: solid black 3px; } button { margin-left: 10px; height: 20px; width: 70px; } </style>
Затем щелкните файл CartView и создайте div с тегом h1.
<template> <div> <h1>This is the cartView page</h1> </div> </template>
Теперь перейдите в папку маршрутизатора и откройте файл index.js. Обновите маршрут и измените его на корзину.
import { createRouter, createWebHistory } from "vue-router"; import HomeView from "../views/HomeView.vue"; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: "/", name: "home", component: HomeView, }, { path: "/cart", name: "cart", component: () => import("../views/CartView.vue"), }, ], }); export default router;
Наконец, перейдите в файл App.vue и создайте новый RouterLink для страницы корзины.
<script setup> import { RouterLink, RouterView} from 'vue-router' </script> <template> <header> <RouterLink to="/"> <h2>Home</h2> </RouterLink> <RouterLink to="/cart"> <h2>Cart</h2> </RouterLink> </header> <RouterView /> </template> <style> header { display: flex; } header :first-child { margin-right: 10px; } </style>
Ваш пользовательский интерфейс должен выглядеть так:
Шаг 4 (Доступ к хранилищу в компонентах Vue)
На следующем шаге мы получим доступ к store и его компонентам из компонентов HomeView и CartView. Откройте файл HomeView.vue и импортируйте useCartStore.
import { useCartStore } from "../stores/cart";
Теперь создайте константу с именем store и назначьте ей нашу функцию useCartStore.
const store = useCartStore();
Затем деструктурируйте нужные вам методы из хранилища. В данном случае нам понадобится только действие addItems.
const { addItems } = store;
Свяжите действие addItems с кнопкой, которая будет действовать при нажатии. Не забудьте передать выбранный элемент в качестве аргумента.
<button @click="addItems(item)">Add</button>
Затем перейдите к файлу CartView.vue и файлу useCartStore.
<script setup>import {useCartStore} from '../stores/cart'</script>
Создайте константу с именем store, которому вы назначите useCartStore, и деструктурируйте действие removeItem и метод получения sortedItems из хранилища.
const store = useCartStore(); const { removeItems, sortedItems } = store;
Поскольку массив carsItems, который мы будем отображать, постоянно меняется, нам понадобится метод Pinia под названием storeToRefs.
storeToRefs — это метод Pinia, который делает состояние реактивным.
Прямой доступ к массиву carsItems может вызвать проблемы с реактивностью (массив не будет обновляться, когда это должно произойти). Итак, storeToRef добавит реактивность состоянию.
Давайте посмотрим, как это работает: внутри того же файла импортируйте storeToRef из Pinia.
import { storeToRefs } from "pinia";
Деструктурируйте элемент carsItems из экземпляра storeToRef, который вы присвоите константе. Передайте переменную store в качестве аргумента
const { cartItems } = storeToRefs(store);
Теперь перейдите к тегу шаблона и сопоставьте массив carsItems, чтобы отобразить добавленные элементы с кнопкой удаления в цикле.
<template> <h1>This is the cart page</h1> <main v-if="cartItems.length > 0"> <div v-for="item in cartItems" :key="item.id" class="item"> <h1></h1> <button>Remove</button> </div> </main> <main v-else> <h2>There is nothing in your cart</h2> </main> </template>
Из приведенного выше кода вы можете видеть, что мы создали условие, которое будет отображать тег h2, когда внутри массива carsItems ничего нет. Далее свяжите действие RemoveItem с кнопкой удаления, чтобы удалить элемент при нажатии на него. Обязательно передайте идентификатор элемента в качестве аргумента.
<button @click="removeItems(item.id)">Remove</button>
Вы захотите, чтобы элементы, которые вы недавно добавили, отображались первыми. Для этого замените carsItems на sortedItems в цикле v-for и деструктурируйте его из storeToRefs, чтобы сделать его реактивным.
<script setup> import { useCartStore } from '../stores/cart' import { storeToRefs } from 'pinia' const store = useCartStore() const { removeItems } = store const { cartItems, sortedItems } = storeToRefs(store) </script> <template> <h1>This is the cart page</h1> <main v-if="sortedItems.length > 0"> <div v-for="item in sortedItems" :key="item.id" class="item"> <h1></h1> <button @click="removeItems(item.id)">Remove</button> </div> </main> <main v-else> <h2>There is nothing in your cart</h2> </main> </template>
Это руководство не будет полным, если мы не протестируем наши коды в пользовательском интерфейсе. Итак, зайдите в браузер, где работает localhost:5173 , и нажмите любую кнопку добавления.
Перейдите на страницу корзины. Вы должны увидеть добавленный вами элемент на странице.
Нажмите кнопку «Удалить», чтобы удалить элемент со страницы.
Шаг 5 (Инструменты разработчика Pinia)
Инструменты разработчика Pinia предоставляются vue, чтобы сделать ваш опыт разработки менее напряженным и более интересным. Таким образом, вы можете протестировать свой store и модификаторы в консоли без необходимости использования пользовательского интерфейса. Чтобы получить доступ к инструментам разработчика Pinia, перейдите в интернет-магазин Chrome и найдите инструменты разработчика vue.js.
Если он у вас уже установлен, как и у нас, на кнопке отобразится «удалить из Chrome», иначе отобразится «Добавить в Chrome». Нажмите кнопку, чтобы загрузить его.
Когда добавлены инструменты разработчика vue, для получения инструментов разработчика Pinia нет необходимости выполнять дальнейшие настройки. Инструменты разработчика Vue проверяют ваш веб-сайт vue и автоматически генерируют инструменты разработчика для любого пакета vue, установленного в вашей кодовой базе. Итак, откройте консоль, нажмите vue и перезагрузите веб-страницу. Инструменты разработчика Vue должны взять Pinia из вашего пакета и сгенерировать для него инструменты разработчика.
На изображении выше вы можете видеть, что инструменты разработчика Pinia отображают ваше состояние и геттеры. Таким образом, с консоли вы можете добавлять новые значения, удалять их и с легкостью сбрасывать состояние.
Заключение
В ходе этой статьи мы обсудили концепцию управления состоянием с помощью Pinia, настройку состояния и модификаций, универсальный доступ к состоянию без ошибок и инструменты разработчика Pinia. Для дальнейшего изучения посетите документацию Pinia.