【vue3 Pinia使用与讲解】vue3新一代的Store应用工具

本文章旨在快速帮助上手Pinia基础与核心部分,想要完整了解的请看官网或后续文章,Pinia 还可用于SSR。还有:这中文名可以叫菠萝,起源是西班牙语piña,中文译为菠萝。

Pinia概要:

Pinia一开始是为了探索Vuex的下一次迭代会是什么样子,它融合了Vuex 5核心团队讨论中的许多想法。
最终,我们意识到Pinia已经实现了Vuex 5中我们想要的大部分功能,并决定将 Pinia 作为新的推荐。

与 Vuex 相比,Pinia 提供了一个更简单的 API,没那么死板,提供了 Composition-API 风格的 API,
在与 TypeScript 一起使用时具有更好的类型推断支持。


什么是 Pinia Store ?

Store(比如Pinia)是一个独立存在的,它保存状态和业务逻辑,而不绑定到组件树。
换句话说,它是全局状态的主人。
它有点像一个组件,一直存在着,每个人都可以读写。
它包含三个概念,state、getters 和 actions,可以理解为这些概念相当于组件中的data、computed 和 methods。


什么时候应该使用 Store ?

存储应该包含可以在整个应用程序中访问的数据。
这包括在许多地方使用的数据,例如在导航栏中显示的用户信息,以及需要通过页面保存的数据,例如非常复杂的多步骤表单。
另一方面,您应该避免在 Store 中存储一个组件里的内部数据,例如组件模板内元素的可见性。
并非所有应用程序都需要访问全局状态,但如果您需要一个,Pinia会让你的开发更轻松。


Pinia 的主要 Api

  * createPinia
    - Plugins
  * defineStore  >>  声明一个Store
  * storeToRefs  >>  见`4.`使用案例
  * mapState  >> 在vue组件的options的computed中使用
  * mapGetters  >> mapState的别名,改用mapState
  * mapActions  >> 在vue组件的options的methods中使用
  * getActivePinia  >> 获取当前活动的 pinia 实例(如果有)。
- Store的核心配置:
  + State
  + Getters
  + Actions


vite + vue3 使用方式:

1. npm install pinia

    (当前文章使用的最新版本:2.0.11,若pinia版本变动导致写法不一致,本文章会持续更新)

2. 创建一个 pinia(根存储)并将其传递给vue应用实例:

import { createApp,h } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
const app = createApp(App)
app.use(createPinia())

3. 定义 Store

在深入研究核心概念之前,我们需要知道 Pinia 是使用 defineStore() 定义的,并且它需要一个唯一的 name 作为第一个参数传递:
name(也称为id)是必需的,Pinia使用 name 参数将 Store 连接到 devtools。
将返回的函数命名为 `use…` 是一种跨组件的约定,使其用法规范化。

  • defineStore(name,options)
    • name: 必传,类型`string`
    • options:{}
import { defineStore } from 'pinia'
// useStore可以是任何类似useUser、useCart的东西
// 第一个参数是应用程序中 Store 的唯一id
export const useStore = defineStore('main', {
  // state: () => ({ count: 0 }),
  state:()=>{
    return {
      // 所有这些属性都将自动推断其数据类型
      items: [],
      counter: 0,
      name: 'Eduardo',
      isAdmin: true,
    }
  },
  getters: {
    doubleCount: (state) => state.counter * 2,
    //doubleCount(state){
    //  console.log(this,'想要在getter中获取该store的其他内容则不能用箭头函数,')
    //  return state.counter * 2
    //},
  },
  actions: {
    increment(num,test1,test2) {
      console.log(num,test1,test2)
      this.counter++
    },
    randomizeCounter() {
      this.counter = Math.round(100 * Math.random())
    },
  }
})



4. 使用 Store

我们之所以声明store,是因为在`setup()`内部调用`useStore()`之前不会创建存储:

还有,不要看到不是



定义多个 Store

这种基本完爆vuex的modules,任何不相关的模块直接单独定义一个新store。任意组件、任意store想要使用任意一个或多个store都没问题。

您可以根据需要定义任意数量的Store,并且应该在不同的文件中定义每个Store以充分利用 pinia(例如自动允许您的包进行代码拆分和 TypeScript 推理)。

一旦 Store 被实例化,您就可以直接访问存储上的state、getter和actions中定义的任何属性。

// otherStore.ts

import { defineStore } from 'pinia'
export const useOtherStore = defineStore('otherStore', {
  state: () => ({
    count: 2
  }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
})

在其他store中使用otherStore ↓↓↓  >>>  useOtherStore()

// index.ts

import { defineStore } from 'pinia'
import { useOtherStore } from './otherStore'
export const useStore = defineStore('main', {
  state:()=>{
    return {
      // 所有这些属性都将自动推断其数据类型
      items: [],
      counter: 2,
      name: 'Eduardo',
      isAdmin: true,
    }
  },
  getters: {
    doubleCount(state) {
      return this.counter * 2
    },
  },
  actions: {
    increment(num,test1,test2?:string) {
      console.log(useOtherStore());
      console.log(num,test1,test2)
      this.counter++
    },
    randomizeCounter() {
      this.counter = Math.round(100 * Math.random())
    },
  }
})


 注意事项!

// 注意,store 是一个用 reactive 包装的对象,意味着不需要在 getters 后面写 .value ;
// 所以就像 props 在 setup 中一样,不能对其进行 对象解构 操作!
export default defineComponent({
  setup(props) {
    const store = useStore()
    // ❌ 这不起作用,因为它会破坏响应式  >>  This won't work because it breaks reactivity
    // 这跟从`props`解构的原理相同  >>  it's the same as destructuring from `props`
    const { name, doubleCount } = store
    console.log(name) // "eduardo"
    console.log(doubleCount) // 2
    return {
      // 永远都是"eduardo"  >> will always be "eduardo"
      name,
      // will always be 2
      doubleCount,
      // 这种就是正常的响应式数据 >> this one will be reactive
      doubleValue: computed(() => store.doubleCount),
      }
  },
})


为了从 Store 中提取属性同时保持其数据的响应性,您需要使用storeToRefs(). 它将为任何响应性属性创建 refs。
当您仅使用商店中的state但不调用任何action时,这很有用:

import { storeToRefs } from 'pinia'
export default defineComponent({
  setup() {
    const store = useStore()
    // `name` 和 `doubleCount` 是响应式 refs 数据
    // 这还将为插件添加的属性创建引用
    // 但会跳过任何 action 和 不是reactive(非ref/reactive)的属性
    const { name, doubleCount } = storeToRefs(store)

    return {
      name,
      doubleCount
    }
  },
})

QQ交流群:522976012  ,欢迎来玩。

聚焦vue3,但不限于vue,任何前端问题,究其本质,值得讨论,研究与学习。

你可能感兴趣的:(前端,vue,javascript,typescript,javascript,前端)