Vue06-Pinia
Pinia
Pinia是西班牙语piña(西班牙语中的“菠萝”)单词的形似。
它是一个状态管理的库,用于跨组件、页面进行状态共享(这点和Vuex、Redux一样),同时兼容Vue2、Vue3,也并不要求你使用Composition API;
Pinia开始于大概2019年,最初是作为一个实验,目的为了探索 Vuex 的下一次迭代会是什么样子,所以它结合了 Vuex 5 核心团队讨论中的许多想法,为Vue重新设计状态管理,让它用起来像组合式API(Composition API)。
最终,团队意识到Pinia已经实现了Vuex5中大部分内容,所以最终决定用Pinia来替代Vuex;
与 Vuex 相比,Pinia 提供了一个更简单的 API,具有更少的仪式,提供了 Composition-API 风格的 API;
最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持;
和Vuex相比,Pinia有很多的优势:
- 比如mutations 不再存在;
- 更友好的TypeScript支持,Vuex之前对TS(TypeScript)的支持很不友好;
- 不再有modules的嵌套结构,
- 也不再有命名空间的概念。
01. 安装Pinia
npm install pinia
或者:
yarn add pinia
02. 案例入门
目录结构。
与vuex类似,对于pinia的使用,编程习惯上一般创建“stores”文件夹。
也常见取名为“pinia”。
在index.js文件中,创建一个全局的pinia实例。
import {createPinia} from 'pinia' const pinia = createPinia() export default pinia
创建好之后,在全局的main.js文件中,使用这个实例。
import {createApp} from 'vue' // 不支持template选项 // import {createApp} from 'vue/dist/vue.esm-browser' // 支持template选项 import App from './App.vue' import pinia from './stores/index' createApp(App).use(pinia).mount('#app')
对于业务逻辑,可以根据模块的不同,将需要管理的state抽离,建立单独的文件,比如counter.js。
定义一个Store:
Store 是使用 defineStore() 定义的,
它需要一个唯一名称,作为第一个参数传递;第二个参数为具体的对象。
defineStore返回的是一个函数,在命名上,统一使用useX作为命名方案,这是约定的规范。
使用defineStore定义的store,默认会与创建的全局pinia关联,可以在组件中直接调用,无需其他操作。
import {defineStore} from 'pinia' // defineStore第一个参数为name,也称为id,是必传参数。唯一标识Store const useCounter = defineStore('counter',{ state:()=>({ count:99 }) }) export default useCounter
HomeCom.vue
<template> <h1>Home Page</h1> <!-- 注意这里与vuex不同 --> <p>Home中的count计数:{{counterStore.count}}</p> <button @click="addCount">count+1</button> </template> <script setup> import useCounter from '@/stores/counter' import {toRefs} from "vue"; import {storeToRefs} from "pinia"; // 执行函数,拿到Store const counterStore = useCounter() // pinia支持直接修改state,不必像vuex那样commit一个mutation function addCount(){ counterStore.count++ } // 需要注意的是,直接对Store进行解构,会失去响应式 // const {count} = counterStore // 保留响应式,可以使用vue提供的方法 // const {count} = toRefs(counterStore) // 保留响应式,pinia也专门提供了一个方法 const {count} = storeToRefs(counterStore) </script> <style scoped> </style>
03. Store
在应用程序中,可以定义任意数量的Store来管理应用程序的状态,
Store有三个核心概念:state、getters、actions;
类似于组件的data、computed、methods;
Store在它被使用之前是不会创建的,使用defineStore函数定义Store时,返回的是一个函数,
调用这个函数,才会创建对应的 store 。
编程习惯:定义Store时,一般以useX的形式。
04. State
对于state,pinia支持直接修改,不同像vuex那样通过mutation。
pinia也支持一次性修改多个state,用 Store.$patch()
,传入一个对象。
对于Store的内部方法,以$开头。
pinia支持直接替换state对象和重置对象。
stores/user.js:
import { defineStore } from 'pinia' const useUser = defineStore("user", { state: () => ({ name: "Mark", age: 18, score: 100 }) }) export default useUser
Home.vue
<template> <div class="home"> <h2>Home View</h2> <h2>name: {{ name }}</h2> <h2>age: {{ age }}</h2> <h2>level: {{ score }}</h2> <button @click="changeState">修改state</button> <button @click="resetState">重置state</button> </div> </template> <script setup> import useUser from '@/stores/user' import { storeToRefs } from 'pinia'; const userStore = useUser() const { name, age, score } = storeToRefs(userStore) function changeState() { // 1.一个个修改状态 // userStore.name = "kobe" // userStore.age = 20 // userStore.score = 200 // 2.一次性修改多个状态 // userStore.$patch({ // name: "james", // age: 35 // }) // 3.替换state为新的对象 const oldState = userStore.$state userStore.$state = { name: "curry", score: 200 } console.log(oldState === userStore.$state) // true。pinia这个功能并不是真的直接替换。 } function resetState() { userStore.$reset() } </script>
05. Getters
Getters相当于Store的计算属性:
-
用 defineStore() 中的 getters 属性定义;
-
getters中可以定义接受一个state作为参数的函数;
counter.js:
// 定义关于counter的store import { defineStore } from 'pinia' import useUser from './user' const useCounter = defineStore("counter", { state: () => ({ count: 99, subjects: [ { id: 111, name: "语文" }, { id: 112, name: "英语" }, { id: 113, name: "数学" }, ] }), getters: { // 1.基本使用 doubleCount(state) { return state.count * 2 }, // 2.一个getter引入另外一个getter doubleCountAddOne() { // this是store实例 return this.doubleCount + 1 }, // 3.getters也支持返回一个函数 getFriendById(state) { return function(id) { for (let i = 0; i < state.subjects.length; i++) { const subject = state.friends[i] if (subject.id === id) { return subject } } } }, // 4.getters中用到别的store中的数据 showMessage(state) { // 1.获取user信息 const userStore = useUser() // 2.获取自己的信息 // 3.拼接信息 return `name:${userStore.name}-count:${state.count}` } }, }) export default useCounter
06. Actions
Actions 相当于组件中的 methods。
- 使用 defineStore() 中的 actions 属性定义。
一般网络请求相关的state管理(异步操作),就使用action完成。
import { defineStore } from 'pinia' const useHome = defineStore("home", { state: () => ({ banners: [], recommends: [] }), actions: { async fetchHomeMultidata() { const res = await fetch("http://123.207.32.32:8000/home/multidata") const data = await res.json() this.banners = data.data.banner.list this.recommends = data.data.recommend.list // return new Promise(async (resolve, reject) => { // const res = await fetch("http://123.207.32.32:8000/home/multidata") // const data = await res.json() // this.banners = data.data.banner.list // this.recommends = data.data.recommend.list // resolve("bbb") // }) } } }) export default useHome
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律