npm install pinia
import {createApp } from 'vue'
import './style.css'
import App from './App.vue'
import {
   
    createPinia } from 'pinia'
const app = createApp(App)
app.use(createPinia())//pinia 装入到vue项目中
app.mount('#app')

javascript

state值设置

  完成初始设置后,创建stores文件夹在这个文件夹下面创建一个用于数据共享的store.js文件。这些数据共享文件可以创建多个,并且针对每个不同的业务和功能都要设置一个数据共享文件。在stores文件夹下会保存多个Store 类 型的文件,这些文件名称最好根据所要执行的业务来命名,这样方便查找和维护。

  首先,在store.js文件中导入pinia创建它的引用对象defineStore。你可以通过defineStore对象创建一个store数据共享器,这些数据共享器使用id来标识,代码通过id标识来找到要使用的数据共享器。我们现在创建一个有计数器功能的数据共享器,它的id名称是counter,返回引用的名称是useStoreCounter ,将这个引用设置成导出函数。

import {defineStore } from 'pinia';
export const useStoreCounter = defineStore('counter', {
   
  state: () => ({
    count: 1,
  }),
});

现在定义好了一个计数Store,让我们在App.vue文件中看看是否可以访问和使用它了。导入store数据共享器获得到它的引用useStoreCounter对象,使用useStoreCounter创建一个Store对象counter,在模板中使用这个counter.count获得共享器中的保存的数字内容。

<script setup>
import {useStoreCounter } from './stores/store';
const counter = useStoreCounter();
</script>
<template>
  <h1>Pinia 入门</h1>
  <p>Count:{
  
  { counter.count }}</p>
</template>

html

在多个组件中同时使用共享数据
  使用 Pinia 的目的是为了能够从所有组件都能访问 Store 中定义的数据,那我们来创建一些vue组件来检查它是否能访问到Store中的数据。在components文件夹下新建一个userPinia.vue文件,代码如下内容。

<script setup>
import { useStoreCounter } from '../stores/store';
const counter = useStoreCounter();
</script>
<template>
  <h2>User中使用 Pinia</h2>
  <p>共享数据:{
  
  { counter.count }}</p>
</template>

html

在 App.vue 文件中导入userPinia.vue组件,并在模板中使用这个组件。

<script setup>
import {useStoreCounter } from './stores/store';
import userPinia from './components/userPinia.vue';
const counter = useStoreCounter();
</script>
<template>
  <h1>Pinia 入门</h1>
  <p>Count:{
  
  { counter.count }}</p>
  <userPinia />
</template>

html

actions动作设置

  上面已经介绍在组件中如何使用和访问Store中的state值,那么我们怎么修改Store的state值中的数据呢?在Pinia的defineStore函数中提供了action属性,在这个action属性中可以添加内置方法,使用这些内置方法来修改defineStore中的state值数据。我们要在 store.js 文件里的defineStore 函数中添加一个增量累加函数sumNumber

import {defineStore } from 'pinia';
export const useStoreCounter = defineStore('counter', {
  state: () => ({
    count: 1,
    user: {
        name: 'zht',
        dept: '部门一'
      },
  }),
  //内置执行方法属性
  actions: {
    //累加方法
    sumNumber() {
      this.count++;
    },
  },
});

在App.vue文件中添加一个带有点击事件的按钮,设置点击事件执行Store对象Actions中定义的sumNumber函数

<script setup>
import {useStoreCounter } from './stores/store';
import userPinia from './components/userPinia.vue';
const counter = useStoreCounter();
</script>
<template>
  <h1>Pinia 入门</h1>
  <p>Count:{{ counter.count }}</p>
  <div>
    <h3>名称:{{counter.user.name}}  </h3>
    <button @click="counter.sumNumber">增加 +1</button>
  </div>
  <userPinia />
</template>

在浏览器中点击按钮,count中的数值会增加。这时候大家会发现父组件和子组件中的count值都会同时发生变化。这些数据共享器中的数据是具有反应特性的,更新反映在所有组件中。

我们来修改一下App.vue代码使用解构赋值方式来获得 Store 中的变量和函数引用。在template 标签不在使用 counter. 的方式来操作Store中变量与函数,这样使得代码变得更加简洁。

<script setup>
import {useStoreCounter } from './stores/store';
import userPinia from './components/userPinia.vue';
const {count,sumNumber,user } = useStoreCounter();
</script>

修改数据

direct

 countstore.sum = 666;

patch Object

 countstore.$patch({
        sum:110,
        school:'阿达'
    })

patch Function

patch function:$patch(state => { state.sum = 10 })

方法修改

import { defineStore } from 'pinia'

export const useConuntStore = defineStore('count', {
        actions:{
          inrment(val:number){
             this.sum +=val   
          }      
        },
        //存储数据的地方
        state() {
                return {
                        sum:6,
                        school:'atguigu'
                }
        },
        getters:{}
})

storeToRefs

  • 借助storeToRefsstore中的数据转为ref对象,方便在模板中使用
  • 注意:pinia提供的storeToRefs只会将数据做转换,而VuetoRefs会转换store中数据(包含方法,方法不需要响应式)。
<template>
	<div class="count">
		<h2>当前求和为:{{sum}}</h2>
	</div>
</template>

<script setup lang="ts" name="Count">
  import { useCountStore } from '@/store/count'
  /* 引入storeToRefs */
  import { storeToRefs } from 'pinia'
  /* 得到countStore */
  const countStore = useCountStore()
  /* 使用storeToRefs转换countStore,随后解构 */
  const {sum} = storeToRefs(countStore)
</script>

getters

     // 引入defineStore用于创建store
     import {defineStore} from 'pinia'
     
     // 定义并暴露一个store
     export const useCountStore = defineStore('count',{
       // 动作
       actions:{
         /************/
       },
       // 状态
       state(){
         return {
           sum:1,
           school:'atguigu'
         }
       },
       // 计算
       getters:{
         bigSum:(state):number => state.sum *10,
         upperSchool():string{
           return this. school.toUpperCase()
         }
       }
     })

组件里使用

 const {increment,decrement} = countStore
 let {sum,school,bigSum,upperSchool} = storeToRefs(countStore)

$subscribe

通过 store 的 $subscribe() 方法侦听 state 及其变化


import { useCountStore } from '@/store/count'
const talkStore = useTalkStore()

talkStore.$subscribe((mutate,state)=>{
  console.log('LoveTalk',mutate,state)
  localStorage.setItem('talkList',JSON.stringify(talkList.value))
})

回调参数:state

变化后的完整 state,直接拿到最新数据。

mutation(重点)

描述 “怎么改的”:

mutation.type // 'direct' / 'patch object' / 'patch function'

{解释

direct:直接赋值(countStore.sum = 10)
patch object:$patch({ sum: 10 })
patch function:$patch(state => { state.sum = 10 })

}
mutation.storeId // 当前 store 的 id(如 'count')
mutation.payload // $patch 传的对象(只有 patch object 才有)例如,{ state.sum = 10 }

store组合式写法

import {defineStore} from 'pinia'
import axios from 'axios'
import {nanoid} from 'nanoid'
import {reactive} from 'vue'

export const useTalkStore = defineStore('talk',()=>{
  // talkList就是state
  const talkList = reactive(
    JSON.parse(localStorage.getItem('talkList') as string) || []
  )

  // getATalk函数相当于action
  async function getATalk(){
    // 发请求,下面这行的写法是:连续解构赋值+重命名
    let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
    // 把请求回来的字符串,包装成一个对象
    let obj = {id:nanoid(),title}
    // 放到数组中
    talkList.unshift(obj)
  }

  //getter
  const bigSum = computed(() => sum.value * 10)


  //必须return------------------------------------
  return {talkList,getATalk,bigSum}
})

使用

<template>
    <div class="talk">
        <button @click="talkStore.getATalk">获取一句话</button>
        <ul>
            <li v-for="talk in talkList" :key="talk.id">{{ talk.title }}</li>
        </ul>
    </div>
</template>
<script setup>
import {useTalkStore} from '@/store/talk'
import { storeToRefs } from 'pinia';

const talkStore = useTalkStore()
const {talkList} = storeToRefs(talkStore)

talkStore.$subscribe((mutate,state)=>{
  console.log('LoveTalk',mutate,state)
  localStorage.setItem('talkList',JSON.stringify(talkList.value))
})
</script>

更多推荐