Vue 3.0 pinia状态管理库

前言:

Pinia是Vue的专属状态管理库,它允许你跨组件或页面共享状态


安装与使用 pinia

  • 安装语法:npm install pinia
  • 创建一个pinia(根存储)并将其传递给应用程序
  • main.js中引入
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')

Store

  1. store是一个保存状态和业务逻辑的实体,它并不与你的组件树绑定;换句话说,它承载着全局状态;它有点像一个永远存在的组件,每个组件都可以读取和写入它
  2. store它有三个概念,state、getters和actions,我们可以l理解成组件中的data、computed和methods
  3. 在项目中的src\store文件夹下不同的store.js文件
  4. store是用defineStore(name, function | options)定义的,建议其函数返回的值命名为use…Store方便理解
    a. 参数name:名字,必填值且唯一
    b. 参数function|options:可以是对象或函数形式
    ■ 对象形式【选项模式】,其中配置state、getters和actions选项
    ■ 函数形式【组合模式,类似组件组合式API的书写方式】,定义响应式变量和方法,并且return对应的变量和方法;ref()相当于state,computed()相当于getters,function()相当于actions

选项式写法:

import {
    
     defineStore } from 'pinia'

// 创建 store,并暴露出去
// 参数一:名字,必填值且唯一
// 参数二:选项式书写方式采用对象形式
export const useStore = defineStore('main', {
    
    
    state: () => ({
    
    
        // ……
    }), 
    getters: {
    
    
        // ……
    },
    actions: {
    
    
        // ……
    }
})

组合式写法:

import {
    
     defineStore } from 'pinia'
import {
    
     computed, ref } from 'vue'

// 创建 store,并暴露出去
// 参数一:名字,必填值且唯一
// 参数二:组合式书写方式采用函数形式
export const useStore = defineStore('main', () => {
    
       
    
    // ref 变量  --->  state
    // computed() 计算属性  --->  getters 
    // functions 函数  --->  actions

    return {
    
     
        // 暴露出去 变量,函数,计算属性即可
    }
})

state

state是store的核心部分,主要存储的是共享的数据

1.定义state

store采用的是选项式模式时,state选项为函数返回的对象,在其定义共享的数据
import {
    
     defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
    
    
  	// 共享的数据,为函数返回的对象形式
    state: () => ({
    
    
        age: 27,
        level: 5,
        account: 'SD77842',
        nickname: '自古风流'
    })
})
store采用的是组合式模式时,在其函数内定义的ref变量,最终return出去来提供共享的数据
import {
    
    defineStore} from "pinia";
import {
    
    ref} from "vue";

export const useUserStore = defineStore('user', () => {
    
    
    const age = ref(27)
    const level = ref(5)
    const account = ref('SD77842')
    const nickname = ref('自古风流')
    
    return {
    
     age, level, account, nickname } // 将数据暴露出去,共享给需要的组件
})

2.在组件中使用

1. 在选项式 API 组件中,可以使用mapState(storeObj, array | object)帮助器将状态属性映射为只读计算属性
  a. storeObj引入的store对象
  b. array | object:字符串数组形式或者对象形式
	 ■ 【字符串数组形式】直接将store中state的数据映射为当前组件的计算属性,但是不能自定义名称
     ■ 【对象形式时】key为自定义当前组件的计算属性名,value字符串形式,是store中state的共享数据

提示:

mapState()函数映射到组件中的计算属性是只读的,如果想在组件中响应式修改state的数据,则应该选择mapWritableState()函数来映射计算属性
<script>
import {
    
     mapState, mapWritableState } from 'pinia'
import {
    
     useUserStore } from '@/store/useUserStore'
import UserVue from '@/components/User.vue'

export default {
    
    
    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>
在组合式 API 组件中,直接引入对应的store,通过store对象直接获取和修改state

提示:
如果想在组件中自定义变量来接收store中的state中共享的数据,我们可以这样做:
● 使用computed(() => store.dataName),具有响应式,但是只读形式
● 使用storeToRefs(store)从store解构想要的state,具有响应式,可直接修改,可自定义名称

<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

1. store采用的是选项式模式时,getters选项中声明的函数即为计算属性
	a. 在其函数内可通过this关键字来获取store实例,也可通过方法的第一个参数得到store实例
	b. 如果采用的是箭头函数的话,无法使用this关键字,为了更方便使用store中实例,
	可为其箭头函数设置第一个参数来获取store实例
import {
    
     defineStore } from "pinia"

export const useUserStore = defineStore('user', {
    
    
    state: () => ({
    
    
        birthday: '1992-12-27',
        age: 30
    }),
    // 通过计算得到的新的共享的数据,只读
    // 如果依赖的数据发生变化,则会重新计算
    getters: {
    
    
        month() {
    
    
          	// this 为 store 实例,当然其函数的第一个参数也为 store 实例
            return this.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 '老年'
        }
    }
})
store采用的是组合式模式时,可通过computed()函数通过计算得到新的数据,再将其return暴露出去即可
import {
    
     defineStore } from "pinia"
import {
    
     computed, ref } from "vue"

export const 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. 在组件中使用

选项式API的组件中,访问store中的getters和访问state类似,同样可使用mapState()帮助器将getters属性映射
为只读计算属性

注意:

如果采用mapWritableState()帮助器将store中的getters映射为组件内部的计算属性,依旧可以具有响应式,一旦对其进行修改则会报错
<script>
import {
    
     mapState, mapWritableState } from 'pinia'
import {
    
     useUserStore } from './store/useUserStore'

export default {
    
    
    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>
在组合式API组件中,访问store中的getters和访问state类似,直接引入对应的store,通过store对象直接获取
getters,但是如果对其进行修改则会报错

提示:

如果想将store中的getter中共享的数据映射为本地组件的计算属性,我们可以这样做:

● 使用computed(() => store.getterName),具有响应式,但是只读形式
● 使用storeToRefs(store)从store解构getter依旧是计算属性,所以是只读的,一旦对其进行修改则会报错,但是具有响应式,可自定义名称

<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实例
import {
    
    defineStore} from "pinia"

export const 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
        }
    }
})
store采用的是组合式模式时,可通过声明函数,再将其return暴露出去即可共享其函数
import {
    
    defineStore} from "pinia"
import {
    
    ref} from "vue";

export const useUserStore = defineStore('user', () => {
    
    
    const nickname = ref('自古风流')
    const age = ref(20)

    // 定义函数(注意:形参不要和 ref 名冲突)
    function setUserInfo(user_nickname, user_age) {
    
    
        nickname.value = user_nickname
        age.value = user_age
    }

    function setUserInfoByObject(user) {
    
    
        // 可通过 `this` 来获取当前 store 实例
        nickname.value = user.nickname
        age.value = user.age
    }

    return {
    
    nickname, age, setUserInfo, setUserInfoByObject} // 暴露函数即可共享函数
})

2. 在组件中使用

1. 在选项式 API 组件中,可以使用mapActions(storeObj, array | object)帮助器将actions映射为当前组件的函数
	 a. storeObj引入的store对象
	b. array | object:字符串数组形式或者对象形式
		■ 【字符串数组形式】直接将store中actions的函数映射为当前组件的函数,但是不能自定义名称
		■ 【对象形式时】key为自定义当前组件的函数名,value字符串形式,是store中actions的函数名
<script>
import {
    
    mapActions, mapState} from "pinia"
import {
    
    useUserStore} from "@/store/useUserStore"

export default {
    
    
    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>
在组合式API组件中,直接引入对应的store,通过store对象直接获取actions

提示:

如果想将store中的actions中函数映射为本地组件的函数,可将store解构出对应的函数即可,也可自定应函数名,此处不可通过storeToRefs(store)函数
<script setup>
import {
    
    useUserStore} from "@/store/useUserStore"
import {
    
     storeToRefs } from "pinia"

// 可直接使用 store 执行 actions
const 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>

总结

以上就是vue3.0 pinia状态管理库的介绍和使用。希望本篇文章能够帮助到你,不懂得可以评论区或者私信问我,我也会一 一解答。谢谢观看!
我的其他文章:https://blog.csdn.net/m0_60970928?type=blog

猜你喜欢

转载自blog.csdn.net/m0_60970928/article/details/129142644