目录
前言:
在编写vue里的项目时,必须要用到状态管理库,我们始终绕不开对 Pinia 的使用 ,vue3 中对状态管理库进行了一些重要的更新,在这里分享给大家!
一、什么是 Pinai
Pinia
是Vue
的专属状态管理库,它允许你跨组件或页面共享状态。Pinia
是Vuex4
的升级版,也就是Vuex5
Pinia
极大的简化了Vuex
的使用,是Vue3
的新的状态管理工具Pinia
对ts
的支持更好,性能更优, 体积更小,无mutations
,可用于Vue2
和Vue3
Pinia
支持Vue Devtools
、 模块热更新和服务端渲染Pinia
的官方地址为:https://pinia.vuejs.org/
二、安装与使用pinia
- 安装语法:
npm install pinia
- 创建一个
pinia
(根存储)并将其传递给应用程序
import{ createApp }from'vue'import App from'./App.vue'// 引入 createPinia 函数import{ createPinia }from'pinia'const app =createApp(App)// 使用 createPinia() 来创建 Pinia(根存储),并应用到整个应用中
app.use(createPinia())
app.mount('#app')
- 在
src
文件下创建一个store
文件夹,并添加store.js
文件。
三、什么是 store
store
是一个保存状态和业务逻辑的实体,它并不与你的组件树绑定;换句话说,它承载着全局状态;它有点像一个永远存在的组件,每个组件都可以读取和写入它store
它有三个概念,state
、getters
和actions
,我们可以l理解成组件中的data
、computed
和methods
- 在项目中的
src\store
文件夹下不同的store.js
文件 store
是用defineStore(name, function | options)
定义的,建议其函数返回的值命名为use...Store
方便理解 1. 参数name
:名字,必填值且唯一2. 参数function|options
:可以是对象或函数形式 - 对象形式【选项模式】,其中配置state
、getters
和actions
选项- 函数形式【组合模式,类似组件组合式API
的书写方式】,定义响应式变量和方法,并且return
对应的变量和方法;ref()
相当于state
,computed()
相当于getters
,function()
相当于actions
选项式:
import{ defineStore }from'pinia'// 创建 store,并暴露出去// 参数一:名字,必填值且唯一// 参数二:选项式书写方式采用对象形式exportconst useStore =defineStore('main',{state:()=>({// ……}),getters:{// ……},actions:{// ……}})
组合式:
import{ defineStore }from'pinia'import{ computed, ref }from'vue'// 创建 store,并暴露出去// 参数一:名字,必填值且唯一// 参数二:组合式书写方式采用函数形式exportconst useStore =defineStore('main',()=>{// ref 变量 ---> state// computed() 计算属性 ---> getters // functions 函数 ---> actionsreturn{// 暴露出去 变量,函数,计算属性即可}})
四、state
state
是
store
的核心部分,主要存储的是共享的数据。
1. 定义 state
store
采用的是选项式模式时,state
选项为函数返回的对象,在其定义共享的数据store
采用的是组合式模式时,在其函数内定义的ref
变量,最终return
出去来提供共享的数据
选项式:
import{ defineStore }from'pinia'exportconst useUserStore =defineStore('user',{// 共享的数据,为函数返回的对象形式state:()=>({age:27,level:5,account:'SD77842',nickname:'自古风流'})})
组合式:
import{defineStore}from"pinia";import{ref}from"vue";exportconst useUserStore =defineStore('user',()=>{const age =ref(27)const level =ref(5)const account =ref('SD77842')const nickname =ref('自古风流')return{ age, level, account, nickname }// 将数据暴露出去,共享给需要的组件})
2. 组件中访问 state
- 在选项式
API
组件中,可以使用mapState(storeObj, array | object)
帮助器将状态属性映射为只读计算属性 1.storeObj
引入的store
对象2.array | object
:字符串数组形式或者对象形式 - 【字符串数组形式】直接将store
中state
的数据映射为当前组件的计算属性,但是不能自定义名称- 【对象形式时】key
为自定义当前组件的计算属性名,value
字符串形式,是store
中state
的共享数据
提示:
mapState()
函数映射到组件中的计算属性是只读的,如果想在组件中响应式修改
state
的数据,则应该选择
mapWritableState()
函数来映射计算属性
- 在组合式
API
组件中,直接引入对应的store
,通过store
对象直接获取和修改state
提示:
如果想在组件中自定义变量来接收
store
中的
state
中共享的数据,我们可以这样做:
- 使用
computed(() => store.dataName)
,具有响应式,但是只读形式- 使用
storeToRefs(store)
从store
解构想要的state
,具有响应式,可直接修改,可自定义名称
选项式:
<script>import{ mapState, mapWritableState }from'pinia'import{ useUserStore }from'@/store/useUserStore'import UserVue from'@/components/User.vue'exportdefault{components:{ UserVue },computed:{// mapState:将 store 的 state 映射成当前组件的计算属性// 具有响应式,但是是只读// 字符串数组形式:不能自定义计算属性名// 对象形式:可以自定义计算属性名...mapState(useUserStore,['age','level']),...mapState(useUserStore,{user_account:'account',user_nickname:'nickname'}),// mapWritableState 与 mapState 用法类似,区别:它可以响应式的读写映射的计算属性...mapWritableState(useUserStore,['account','nickname']),...mapWritableState(useUserStore,{user_age:'age',user_level:'level'}),}}</script><template><UserVue></UserVue><h2>mapState 映射的计算属性</h2><ul><li>年龄:{{ age }}</li><li>等级:{{ level }}</li><li>账号:{{ user_account }}</li><li>昵称:{{ user_nickname }}</li></ul><button @click="age += 10">更改年龄</button>|<button @click="user_nickname += '='">更改昵称</button><hr><h2>mapWritableState 映射的计算属性</h2><ul><li>年龄:{{ user_age }}</li><li>等级:{{ user_level }}</li><li>账号:{{ account }}</li><li>昵称:{{ nickname }}</li></ul><button @click="user_age += 10">更改年龄</button>|<button @click="nickname += '='">更改昵称</button></template>
组合式:
<script setup>import{ useUserStore }from'@/store/useUserStore'import{ storeToRefs }from'pinia'import{ computed }from'vue'import UserVue from'@/components/User.vue'// 获取 UserStore 实例const user_store =useUserStore()// 通过 computed() 将 store 中 state 映射成当前组件中的计算属性,具有响应性,但是是只读的const user_age =computed(()=> user_store.age)const user_level =computed(()=> user_store.level)const user_account =computed(()=> user_store.account)const user_nickname =computed(()=> user_store.nickname)// storeToRefs 将 store 中 state 解构为组件的数据,具有响应性,还可以响应式修改const{
age,
level,account: userAccount,nickname: userNickname
}=storeToRefs(user_store)</script><template><UserVue></UserVue><h2>从 store 直接取 state </h2><ul><li>年龄:{{ user_store.age }}</li><li>等级:{{ user_store.level }}</li><li>账号:{{ user_store.account }}</li><li>昵称:{{ user_store.nickname }}</li></ul><button @click="user_store.age += 10">更改年龄</button>|<button @click="user_store.nickname += '='">更改昵称</button><hr><h2>computed 映射为计算属性</h2><ul><li>年龄:{{ user_age }}</li><li>等级:{{ user_level }}</li><li>账号:{{ user_account }}</li><li>昵称:{{ user_nickname }}</li></ul><button @click="user_age += 10">更改年龄</button>|<button @click="user_nickname += '='">更改昵称</button><hr><h2>storeToRefs 解构成自己的数据</h2><ul><li>年龄:{{ age }}</li><li>等级:{{ level }}</li><li>账号:{{ userAccount }}</li><li>昵称:{{ userNickname }}</li></ul><button @click="age += 10">更改年龄</button>|<button @click="userNickname += '='">更改昵称</button></template>
五、Getters
getters
是计算得到的新的共享数据,当依赖的数据发生变化时则重新计算,所以其他组件包括
store
自己不要直接对其修改。
1. 定义 Getters
store
采用的是选项式模式时,getters
选项中声明的函数即为计算属性 1. 在其函数内可通过this
关键字来获取store
实例,也可通过方法的第一个参数得到store
实例2. 如果采用的是箭头函数的话,无法使用this
关键字,为了更方便使用store
中实例,可为其箭头函数设置第一个参数来获取store
实例store
采用的是组合式模式时,可通过computed()
函数通过计算得到新的数据,再将其return
暴露出去即可。
选项式:
import{ defineStore }from"pinia"exportconst useUserStore =defineStore('user',{state:()=>({birthday:'1992-12-27',age:30}),// 通过计算得到的新的共享的数据,只读// 如果依赖的数据发生变化,则会重新计算getters:{month(){// this 为 store 实例,当然其函数的第一个参数也为 store 实例returnthis.birthday.split('-')[1]},// 因箭头函数无法使用 `this`,函数的第一个参数为 store 实例ageStage:store=>{if(store.age <18)return'未成年'if(store.age <35)return'青年'if(store.age <50)return'中年'if(store.age >=50)return'老年'}}})
组合式:
import{ defineStore }from"pinia"import{ computed, ref }from"vue"exportconst useUserStore =defineStore('user',()=>{const birthday =ref('1992-12-27')const age =ref(30)// 声明通过计算得到的共享数据,是只读的,如果依赖的数据发生变化则会重新计算const month =computed(()=>{return birthday.value.split('-')[1]})const ageStage =computed(()=>{if(age.value <18)return'未成年'if(age.value <35)return'青年'if(age.value <50)return'中年'if(age.value >=50)return'老年'})return{ birthday, age, month, ageStage }})
2. 在组件中使用 Getters
- 选项式
API
的组件中,访问store
中的getters
和访问state
类似,同样可使用mapState()
帮助器将getters
属性映射为只读计算属性
注意:
如果采用
mapWritableState()
帮助器将
store
中的
getters
映射为组件内部的计算属性,依旧可以具有响应式,一旦对其进行修改则会报错
- 在组合式
API
组件中,访问store
中的getters
和访问state
类似,直接引入对应的store
,通过store
对象直接获取getters
,但是如果对其进行修改则会报错
提示:
如果想将
store
中的
getter
中共享的数据映射为本地组件的计算属性,我们可以这样做:
- 使用
computed(() => store.getterName)
,具有响应式,但是只读形式 使用storeToRefs(store)
从store
解构getter
依旧是计算属性,所以是只读的,一旦对其进行修改则会报错,但是具有响应式,可自定义名称
选项式:
<script>import{ mapState, mapWritableState }from'pinia'import{ useUserStore }from'./store/useUserStore'exportdefault{computed:{// 从 store 中映射 getters 和映射 state 用法相同,都可以用 mapState// 具有响应式,但是是只读的,如果修改了则会警告...mapState(useUserStore,['month']),...mapState(useUserStore,{user_age_stage:'ageStage'}),// 从 store 中 映射 getters 和映射 state 用法相同,都可以用 mapWritableState// 具有响应式,但是是只读的,如果修改了则会报错...mapWritableState(useUserStore,['ageStage']),...mapWritableState(useUserStore,{birthday_month:'month'}),// 把 store 中 stage 解构为自己的计算属性...mapWritableState(useUserStore,['birthday','age'])}}</script><template><h3>mapState 字符串数组形式将 getters 映射成计算属性</h3><ul><li>月份:{{ month }}</li></ul><button @click="month = '5'">更改月份</button><hr><h3>mapState 对象形式将 getters 映射成计算属性</h3><ul><li>年龄阶段:{{ user_age_stage }}</li></ul><button @click="user_age_stage = '未知'">更改年龄阶段</button><hr><h3>mapWritableState 字符串数组形式将 getters 映射成计算属性</h3><ul><li>年龄阶段:{{ ageStage }}</li></ul><button @click="ageStage = '未知'">更改年龄阶段</button><hr><h3>mapWritableState 对象形式将 getters 映射成计算属性</h3><ul><li>月份:{{ birthday_month }}</li></ul><button @click="birthday_month = '5'">更改年龄阶段</button><hr>
生日:<input type="date" v-model="birthday">|
年龄:<input type="number" min="1" max="100" v-model="age"></template>
组合式:
<script setup>import{ storeToRefs }from'pinia'import{ computed }from'vue'import{ useUserStore }from'./store/useUserStore'// store 实例,可直接通过 store 获取 getters, 但是是只读的,如果一旦修改则会报错const user_store =useUserStore()// 通过 computed 将 getters 映射为自己的计算属性, 但是是只读的,如果一旦修改则会警告const birthday_month =computed(()=> user_store.month)const user_age_stage =computed(()=> user_store.ageStage)// 通过 storeToRefs 将 getters 解构为自己的计算属性, 但是是只读的,如果一旦修改则会警告const{ month,ageStage: userAgeStage }=storeToRefs(user_store)// 将 state 解构为自己的数据const{ birthday, age }=storeToRefs(user_store)</script><template><h3>通过 store 直接获取 getters</h3><ul><li>月份:{{ user_store.month }}</li><li>年龄阶段:{{ user_store.ageStage }}</li></ul><button @click="user_store.month = '5'">更改月份</button>|<button @click="user_store.ageStage = '未知'">更改年龄阶段</button><hr><h3>通过 computed 将 getters 映射为自己的计算属性</h3><ul><li>月份:{{ birthday_month }}</li><li>年龄阶段:{{ user_age_stage }}</li></ul><button @click="birthday_month = '5'">更改月份</button>|<button @click="user_age_stage = '未知'">更改年龄阶段</button><hr><h3>通过 storeToRefs 将 getters 映射为自己的计算属性</h3><ul><li>月份:{{ month }}</li><li>年龄阶段:{{ userAgeStage }}</li></ul><button @click="month = '5'">更改月份</button>|<button @click="userAgeStage = '未知'">更改年龄阶段</button><hr>
生日:<input type="date" v-model="birthday">|
年龄:<input type="number" min="1" max="100" v-model="age"></template>
六、Actions
actions
一般情况下是对
state
中的数据进行修改的业务逻辑函数,
actions
也可以是异步的,您可以在其中
await
任何
API
调用甚至其他操作!
1. 定义Actions
store
采用的是选项式模式时,actions
选项中声明的函数即可共享其函数,在其函数内可通过this
来获取整个store
实例store
采用的是组合式模式时,可通过声明函数,再将其return
暴露出去即可共享其函数
选项式:
import{defineStore}from"pinia"exportconst useUserStore =defineStore('user',{state:()=>({nickname:'自古风流',age:20}),// 定义共享的函数,其主要是修改 state 中的数据的逻辑代码// 其函数可以是异步的actions:{setUserInfo(nickname, age){// 可通过 `this` 来获取当前 store 实例this.nickname = nickname
this.age = age
},setUserInfoByObject(user){this.nickname = user.nickname
this.age = user.age
}}})
组合式:
import{defineStore}from"pinia"import{ref}from"vue";exportconst useUserStore =defineStore('user',()=>{const nickname =ref('自古风流')const age =ref(20)// 定义函数(注意:形参不要和 ref 名冲突)functionsetUserInfo(user_nickname, user_age){
nickname.value = user_nickname
age.value = user_age
}functionsetUserInfoByObject(user){// 可通过 `this` 来获取当前 store 实例
nickname.value = user.nickname
age.value = user.age
}return{nickname, age, setUserInfo, setUserInfoByObject}// 暴露函数即可共享函数})
2. 组件中访问 Actions
- 在选项式
API
组件中,可以使用mapActions(storeObj, array | object)
帮助器将actions
映射为当前组件的函数 1.storeObj
引入的store
对象2. **array | object
**:字符串数组形式或者对象形式 - 【字符串数组形式】直接将store
中actions
的函数映射为当前组件的函数,但是不能自定义名称- 【对象形式时】key
为自定义当前组件的函数名,value
字符串形式,是store
中actions
的函数名 - 在组合式
API
组件中,直接引入对应的store
,通过store
对象直接获取actions
提示:
如果想将
store
中的
actions
中函数映射为本地组件的函数,可将
store
解构出对应的函数即可,也可自定应函数名,此处不可通过
storeToRefs(store)
函数
选项式:
<script>import{mapActions, mapState}from"pinia"import{useUserStore}from"@/store/useUserStore"exportdefault{computed:{...mapState(useUserStore,['nickname','age'])},methods:{// 使用 mapActions 将 store 中的 actions 映射为自己的函数// 采用函数形式,无法自定义映射的函数名// 采用对象形式,可自定义映射的函数名...mapActions(useUserStore,['setUserInfo']),...mapActions(useUserStore,{set_info_by_object:'setUserInfoByObject'})}}</script><template><ul><li>昵称:{{ nickname }}</li><li>昵称:{{ age }}</li></ul><button @click="setUserInfo('Tom', 15)">修改信息</button><button @click="set_info_by_object({ nickname: 'Jack', age: 40})">
修改信息
</button></template>
组合式:
<script setup>import{useUserStore}from"@/store/useUserStore"import{ storeToRefs }from"pinia"// 可直接使用 store 执行 actionsconst user_store =useUserStore()const{nickname, age}=storeToRefs(user_store)// 可将 store 中的 actions 映射为自己的函数,可自定映射的函数名(不可使用 storeToRes 函数)const{setUserInfo,setUserInfoByObject: set_user_info_object}= user_store
</script><template><ul><li>昵称:{{ nickname }}</li><li>昵称:{{ age }}</li></ul><span>直接使用 store 执行 actions:</span><button @click="user_store.setUserInfo('Tom', 15)">修改信息</button><button @click="user_store.setUserInfoByObject({ nickname: 'Jack', age: 40})">
修改信息
</button><hr><span>将 store 中的 actions 映射成自己的函数:</span><button @click="setUserInfo('Annie', 45)">修改信息</button><button @click="set_user_info_object({ nickname: 'Drew', age: 50})">
修改信息
</button></template>
总结:
欢迎大家加入我的社区,在社区中会不定时发布一些精选内容:https://bbs.csdn.net/forums/db95ba6b828b43ababd4ee5e41e8d251?category=10003
以上就是 Vue3 的状态管理库(Pinia),不懂得也可以在评论区里问我或私聊我询问,以后会持续发布一些新的功能,敬请关注。
我的其他文章:https://blog.csdn.net/weixin_62897746?type=blog
版权归原作者 清风 与我 所有, 如有侵权,请联系我们删除。