Vue学习:30-安装与使用Pinia

一、Pinia的安装

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

1、安装语法:npm install pinia 、 pnpm add pinia

2、创建一个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')

3.工作流程

二、Pinia中的store

1、store是一个保存状态和业务逻辑的实体,它并不与你的组件树绑定;换句话说,它承载着全局状态;它有点像一个永远存在的组件,每个组件都可以读取和写入它

2、store它有三个概念:state、getters和actions,我们可以理解成组件中的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

src/store/store.js

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

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

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

三、store中的state

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

(一)定义state

1、store采用的是选项式模式时,state选项为函数返回的对象,在其定义共享的数据

2、store采用的是组合式模式时,在其函数内定义的ref变量,最终return出去来提供共享的数据

src/store/useUserStore.js

import { defineStore } from "pinia";
import { ref } from 'vue'

export const useUserStore = defineStore('user',()=>{
  const age = ref(27)
  const level = ref(5)
  const account = ref('SD78906')
  const nickname = ref('一个好人')

  //将数据暴露出去,共享给需要的组件
  return {
    age,level,account,nickname
  }
})

(二)组件中访问state

在组合式 API 组件中,直接引入对应的store,通过store对象直接获取和修改state

提示:

如果想在组件中自定义变量来接收store中的state中共享的数据,我们可以这样做:

● 使用computed(() => store.dataName),具有响应式,但是只读形式

● 使用storeToRefs(store)从store解构想要的state,具有响应式,可直接修改,可自定义名称

App.vue

<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>

<!-- 视图区域(view) -->
<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>
<style>
 
</style>

User.vue

<script setup>
import { useUserStore } from '@/store/useUserStore'
import { storeToRefs } from 'pinia'

const user_store = useUserStore()

const {
  age,
  level,
  account: userAccount,
  nickname: userNickname
} = storeToRefs(user_store)

</script>

<template>
  <ul>
    <li>年龄:{{ age }}</li>
    <li>等级:{{ level }}</li>
    <li>账号:{{ userAccount }}</li>
    <li>昵称:{{ userNickname }}</li>
  </ul>
</template>

<style scoped>
ul {
  background-color: yellow;
}
</style>

四、store中的getters

getters是计算得到的新的共享数据,当依赖的数据发生变化时则重新计算,所以其他组件包括store自己不要直接对其修改。

(一)定义Getters

1、store采用的是选项式模式时,getters选项中声明的函数即为计算属性

a. 在其函数内可通过this关键字来获取store实例,也可通过方法的第一个参数得到store实例

b. 如果采用的是箭头函数的话,无法使用this关键字,为了更方便使用store中实例,可为其箭头函数设置第一个参数来获取store实例

2、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 }

})

(二)在组件中使用Getters

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

注意:如果采用mapWritableState()帮助器将store中的getters映射为组件内部的计算属性,依旧可以具有响应式,一旦对其进行修改则会报错

2、在组合式API组件中,访问store中的getters和访问state类似,直接引入对应的store,通过store对象直接获取getters,但是如果对其进行修改则会报错

提示:

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

● 使用computed(() => store.getterName),具有响应式,但是只读形式

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

实例:

src/store/useUserStore.js

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 ageState = 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,ageState
  }
})

App.vue

<script setup>
import { useUserStore } from '@/store/useUserStore'
import { storeToRefs } from 'pinia'
import { computed } from 'vue'


//获取UserStore实例,可直接通过store获取getters,但是是只读的,如果一旦修改则会报错  
const user_store = useUserStore()

//通过computed()将store中getters映射成当前组件中的计算属性,但是是只读的,如果一旦修改则会报错
const birthday_month = computed(() => user_store.month)
const user_age_state = computed(() => user_store.ageState)


//storeToRefs将store中getters解构为组件的数据,具有响应性,但是是只读的,如果一旦修改则会报错
const {
  month,
  ageState: userAgeState
} = storeToRefs(user_store)

//将state解构为自己的数据
const { birthday,age } = storeToRefs(user_store)
</script>

<!-- 视图区域(view) -->
<template>
  <h3>通过store直接获取getters</h3>
  <ul>
    <li>月份:{{ user_store.month }}</li>
    <li>年龄阶段:{{ user_store.ageState }}</li>
  </ul>
  <button @click="user_store.month = '5'">更改月份</button>
  <button @click="user_store.ageState = '未知'">更改年龄阶段</button>

  <hr>
  <h3>通过computed将getters映射为自己的计算属性</h3>
  <ul>
    <li>月份:{{ birthday_month }}</li>
    <li>年龄阶段:{{ user_age_state }}</li>
  </ul>
  <button @click="birthday_month = '5'">更改月份</button>
  <button @click="user_age_state = '未知'">更改年龄阶段</button>

  <hr>
  <h3>通过storeToRefs将getters映射为自己的计算属性</h3>
  <ul>
    <li>月份:{{ month }}</li>
    <li>年龄阶段:{{ userAgeState }}</li>
  </ul>
  <button @click="month = '5'">更改月份</button>
  <button @click="userAgeState = '未知'">更改年龄阶段</button>

  <hr>
  生日:<input type="date" v-model="birthday">
  年龄:<input type="number" min="1"  max="120" v-model="age">

</template>
<style>
 
</style>

五、store中的actions

actions一般情况下是对state中的数据进行修改的业务逻辑函数,actions也可以是异步的,您可以在其中await任何API调用甚至其他操作!

(一)定义Actions

1、store采用的是选项式模式时,actions选项中声明的函数即可共享其函数,在其函数内可通过this来获取整个store实例

2、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} // 暴露函数即可共享函数
})

(二)组件中访问Actions

1、在选项式 API 组件中,可以使用mapActions(storeObj, array | object)帮助器将actions映射为当前组件的函数

a. storeObj引入的store对象

b. array | object:字符串数组形式或者对象形式

■ 【字符串数组形式】直接将store中actions的函数映射为当前组件的函数,但是不能自定义名称

■ 【对象形式时】key为自定义当前组件的函数名,value字符串形式,是store中actions的函数名

2、在组合式API组件中,直接引入对应的store,通过store对象直接获取actions

提示:如果想将store中的actions中函数映射为本地组件的函数,可将store解构出对应的函数即可,也可自定应函数名,此处不可通过storeToRefs(store)函数

实例:

useUserStore.js

import { defineStore } from "pinia";
import { computed,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
  }
})

App.vue

<script setup>
import { useUserStore } from '@/store/useUserStore'
import { storeToRefs } from 'pinia'


//获取UserStore实例  
const user_store = useUserStore()

const {nickname,age} = storeToRefs(user_store)

//可将store中的actions映射为自己的函数,可自定义映射的函数名(不可使用storeToRefs函数)
const {setUserInfo,setUserInfoByObject:set_user_info_object} = user_store

</script>

<!-- 视图区域(view) -->
<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: 'John',age: 40})">修改信息</button>

  <hr>
  <span>将store中的actions映射成自己的函数:</span>
  <button @click="setUserInfo('Mike',35)">修改信息</button>
  <button @click="set_user_info_object({nickname: 'Yadown',age: 20})">修改信息</button>

</template>
<style>
 
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值