您现在的位置是:首页 >技术教程 >pinia的使用网站首页技术教程

pinia的使用

小曲曲 2023-06-13 00:00:03
简介pinia的使用

介绍

  • 一个拥有组合式 API 的 Vue 状态管理库
  • 主要是面向 Vue 3 的用户,除了安装和 SSR 两章之外,其余章节中提到的 API 均支持 Vue 2 和 Vue
  • Devtools 支持,追踪 actions、mutations 的时间线,在组件中展示它们所用到的 Store,让调试更容易的 Time travel
  • 热更新。不必重载页面即可修改 Store,开发时可保持当前的 State
  • 插件:可通过插件扩展 Pinia 功能
  • 为 JS 开发者提供适当的 TypeScript 支持以及自动补全功能。
  • 支持服务端渲染

对比 Vuex

  • 与 Vuex 相比,Pinia 提供了一个更简单的 API,mutation 已被弃用
  • 提供了符合组合式 API 风格的 API,也可使用选项式API
  • 搭配 TypeScript 一起使用时有非常可靠的类型推断支持
  • Pinia 从设计上提供的是一个扁平的结构,不再有嵌套结构的模块,不再有可命名的modules。但可以通过导入和使用另一个 Store 来隐含地嵌套 stores 空间。

使用

yarn add pinia 
npm install pinia 
----------------------------------
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const pinia = createPinia()
const app = createApp(App)

app.use(pinia)
app.mount('#app')

定义store文件

  • 在store文件夹下新建user.js
  • defineStore定义一个store
    • 第一个参数是你的应用中 Store 的唯一 ID
    • 第二个参数可接受两类值:Setup 函数或 Option 对象
    • 仓库最好使用 store 的名字,同时以 use 开头且以 Store 结尾。(比如 useUserStoreuseCartStoreuseProductStore)
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
})

Option Store 类似选项式API

export const useUserStore = defineStore('User', {
  state: () => {
    return {
      count: 0, // 所有这些属性都将自动推断出它们的类型
    }
  },
  getters: {
    doubleCount: (state) => state.count * 2,
    doubleCountPlus() { 
      return this.doubleCount + 1
    },
  },
  actions: {
    increment() {
      this.count++
    },
  },
})

Setup Store 类似组合式API 的 setup 函数

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  function increment() {
    count.value++
  }
  return { count, increment }
})

使用 Store

  • store 是一个用 reactive 包装的对象,所以使用方式和reactive对象一样
<script setup>
import { useUserStore } from '@/store/user' 
const userStore= useUserStore()


// ------------使用变量------
// userStore 是一个用 reactive 包装的对象
let count = userStore.count
// 所以reactive对象的属性不具有响应式,所以不能解构直接使用
// 若想解构,先将它每一个属性转化为响应式,类似roRefs()
import { storeToRefs } from 'pinia'
const { name, doubleCount } = storeToRefs(userStore)


// ----------使用方法---------
userStore.increment() 
//或者解构:actions 的 increment 方法可以直接解构
const { increment } = userStore
increment()
</script>

修改state的三种方法

  • 直接在页面组件中改变数据
  • 使用$patch改变数据
    • patch object:是通过我们熟悉的 $patch 的 对象方式 来变化
    • patch function:也是通过 $patch,但是是通过 函数的方式 来变化
  • direct:通过 action 变化
  • 重置数据
<template>
  <div>baseUrl:{{ baseUrl }}</div>
  <div>ipList:{{ ipList }}</div>
  <button @click="changeData">直接在页面组件中改变数据</button>
  <button @click="changeDataByPatch">使用$patch改变数据</button>
  <button @click="changeDataByAction">使用action改变数据</button>
  <button @click="resetData">重置数据</button>
</template>
 
<script setup>
import useAppStore from "@/store/modules/app"
import { storeToRefs } from "pinia"
const store = useAppStore()
let { baseUrl, ipList } = storeToRefs(store)

/* 第一种修改方式:虽然可以直接修改,但是出于代码结构来说,
*               全局的状态管理还是不要直接在各个组件处随意修改状态,
*               应放于 action 中统一方法修改(piain没有mutation)
*               并不推荐!!!
* */
function changeData() { 
  store.baseUrl = 'https://www.taobao.com/'  
  store.ipList.push('192.168.10.111')  
}

/*第二种修改方式:使用$patch改变数据, $patch 可以同时修改多个值
 *  $patch也有两种的调用方式
 *  第一种写法的在修改数组时,假如我只想修改 ipList 的中第2项 , 也需要传入整个数组, 所以一般都推荐使用第二种传入一个函数的写法
 */
function changeDataByPatch() {
  // 第一种 $patch方法
  store.$patch({
     baseUrl: 'https://www.jd.com/',
     ipList: ['192.168.10.777', '192.168.10.222', '192.168.10.888']
  })

  // 第二种 $patch方法
  store.$patch((state) => {
    state.baseUrl = 'https://www.jd.com/'
    state.ipList[1] = '192.168.10.222'
  })
}

// 第三种修改方式:调用store中的action改变数据的方法changeState
function changeDataByAction() {
  store.changeState('https://www.alibabagroup.com/cn/global/home')  //可以直接给actions里面的方法传递参数
}

// 重置数据
function resetData() {
  store.$reset()
}

</script>

订阅$subscribe:监听 state 里面的值是否发生了变化

cartStore.$subscribe((mutation, state) => {
  console.log(mutation, state)
  // mutation.type //发生改变的三种方式: 'direct' | 'patch object' | 'patch function' 
  // mutation.storeId // store名字
  // mutation.payload // 传递给 cartStore.$patch() 的对象。只有 mutation.type === 'patch object'的情况下才可用
  // 每当状态发生变化时,将整个 state 持久化到本地存储。
  localStorage.setItem('cart', JSON.stringify(state))
})
//subscription 会被绑定到添加它们的组件上 ,当该组件被卸载时,它们将被自动删除。如果想保留,设置 { detached: true } ,以将 state subscription 从当前组件中分离
cartStore.$subscribe(callback, { detached: true })

当前 getter 访问其他 store 的 getter

import { useOtherStore } from './other-store'
export const useStore = defineStore('main', {
  getters: {
    otherGetter(state) {
      const otherStore = useOtherStore()
      return state.localData + otherStore.data
    },
  },
})

订阅 action

const unsubscribe = someStore.$onAction(
  ({
    name, // action 名称
    store, // store 实例,类似 `someStore`
    args, // 传递给 action 的参数数组
    after, // 在 action 返回或解决后的钩子
    onError, // action 抛出或拒绝的钩子
  }) => {
    // 为这个特定的 action 调用提供一个共享变量
    const startTime = Date.now()
    // 这将在执行 "store "的 action 之前触发。
    console.log(`Start "${name}" with params [${args.join(', ')}].`)

    // 这将在 action 成功并完全运行后触发。
    // 它等待着任何返回的 promise
    after((result) => {
      console.log(
        `Finished "${name}" after ${
          Date.now() - startTime
        }ms.
Result: ${result}.`
      )
    })

    // 如果 action 抛出或返回一个拒绝的 promise,这将触发
    onError((error) => {
      console.warn(
        `Failed "${name}" after ${Date.now() - startTime}ms.
Error: ${error}.`
      )
    })
  }
)

// 手动删除监听器
unsubscribe()

// 此订阅器即便在组件卸载之后仍会被保留
someStore.$onAction(callback, true)
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。