Pinia快速入门

前言

Pinia和Vuex有很多相似之处,它们都是用于实现状态管理的插件。但是,Pinia相对于Vuex来说,更加轻量,并且提供了更多的功能,例如支持异步状态更新、更好的调试能力等🍍🥭🍎。


一、🍍什么是Pinia

Pinia是Vue的专属的最新状态管理库,是Vuex状态管理工具的替代品

优势:

  1. 提供了更加简单的API(去掉了mutation)
  2. 提供符合组合式风格的API(和Vue3新语法统一)
  3. 去掉modules的概念,每一个store都是独立的模块
  4. 搭配TypeScript一起使用提供可靠的类型推断

1. 创建Vue空项目

shell 复制代码
npm init vue@latest

使用VScode打开项目,并安装依赖,然后运行项目

shell 复制代码
cd vue-pinia
npm install
npm run dev

项目创建完成

2. 安装Pinia

shell 复制代码
npm install pinia

3. 将Pinia挂载到vue项目中

main.js

js 复制代码
import './assets/main.css'

import { createApp } from 'vue'
import App from './App.vue'

//1. 导入createPinia
import {createPinia} from 'pinia'

//2. 执行方法得到实例
const pinia=createPinia()

//3. 将pinia实例加入到app中
createApp(App).use(pinia).mount('#app')

Pinia在vue中是以插件的形式存在。

二、🥞Pinia基础使用

1. 官网案例

核心步骤:

  1. 定义Store

    stores/counter.js

    js 复制代码
    import { defineStore } from 'pinia'
    import { ref } from 'vue'
    export const useCounterStore = defineStore('counter', () => {
        //数据(state)
        const count = ref(0)
    
        //定义修改数据的方法(action 同步+异步)
        const increment = () => {
            count.value++
        }
    
        //以对象的形式返回
        return { count, increment }
    })

    官方提示:

    1. 你可以对 defineStore()的返回值进行任意命名,但最好使用 store 的名字,同时以 use开头且以 Store结尾。(比如 useUserStore,useCartStore,useProductStore)

    2. 第一个参数是你的应用中 Store 的唯一 ID。

    3. defineStore() 的第二个参数可接受两类值:Setup 函数或 Option 对象。

  2. 在组件中使用store

    App.vue

    js 复制代码
    <script setup>
      //1. 引入方法
      import {useCounterStore} from '@/stores/counter'
    
      //2. 执行方法得到store实例
      const counterStore=useCounterStore()
      console.log(counterStore);
    </script>
    
    <template>
      <button @click="counterStore.increment">{{counterStore.count}}</button>
    </template>

2. getter实现

Pinia中的getters直接使用computed函数进行模拟。

Getter 完全等同于 store 的 state 的计算值。可以通过 defineStore() 中的 getters属性来定义它们。推荐使用箭头函数,并且它将接收 state作为第一个参数.

stores/counter.js

js 复制代码
import {defineStore} from 'pinia'
import {computed, ref} from 'vue'

export const useCounterStore = defineStore('counter', () => {
    //数据(state)

    const count = ref(0)

    //定义修改数据的方法
    const increment = () => {
        count.value++
    }

    //定义getter
    const doubleCount = computed(() => count.value * 2)

    //以对象的形式返回
    return {count, increment, doubleCount}
})

App.vue

js 复制代码
<script setup>
  //引入方法
  import {useCounterStore} from '@/stores/counter'

  //执行方法得到store实例
  const counterStore=useCounterStore()
  console.log(counterStore);
</script>

<template>
  <button @click="counterStore.increment">{{counterStore.count}}</button><br>

  <div>这是刚刚定义的doubleCount:{{ counterStore.doubleCount}}</div>

</template>

大多数时候,getter 仅依赖 state,不过,有时它们也可能会使用其他 getter。因此,即使在使用常规函数定义 getter 时,我们也可以通过 this访问到整个 store 实例,但(在 TypeScript 中)必须定义返回类型。这是为了避免 TypeScript 的已知缺陷,不过这不影响用箭头函数定义的 getter,也不会影响不使用 this 的 getter。

3. action如何异步实现

action中实现异步和组件中定义数据和方法的风格完全一致

先安装axios

shell 复制代码
npm install axios

stores/counter.js

此处创建了一个异步的action用来请求一个列表数据,和一个响应式的列表用来存储数据(我把之前的内容删掉了,以免产生误导,还是原来的两个文件)

js 复制代码
import {defineStore} from 'pinia'
import {computed, ref} from 'vue'
import axios from "axios";

export const useCounterStore = defineStore('counter', () => {
    //定义一个异步action
    const list = ref([])
    const getList = async () => {

        //此接口已经失效,无法发起请求,只能模拟一下数据,意思意思
        // const response = await axios.get("http://geek.itheima.net/y1_0/channels")

        // response.data.data.channels返回的就是一个列表,下面用模拟数据演示
        // list.value = response.data.data.channels
        list.value = ['模拟数据1', '模拟数据2', '模拟数据3', '模拟数据4', '模拟数据5', '模拟数据6']
    }
    //以对象的形式返回
    return {list, getList}
})

App.vue

js 复制代码
<script setup>

import {useCounterStore} from '@/stores/counter'
import {onMounted} from "vue";

const counterStore = useCounterStore()
console.log(counterStore);

onMounted(() => {
  counterStore.getList()
})
</script>

<template>
  <ul>
    <li v-for="item in counterStore.list" >{{item}}</li>
  </ul>
</template>

注意:此处把axios的请求注释掉完全是无奈之举,不注释掉会报错,导致模拟数据也无法渲染

4. storeToRefs函数

使用storeToRefs函数可以辅助保持数据 (state + getter) 的响应式解构

错误示范:直接解构赋值(响应式丢失)

js 复制代码
<script setup>
import {useCounterStore} from '@/stores/counter'

const counterStore = useCounterStore()

//直接解构赋值
const {count, doubleCount} = useCounterStore()

</script>

<template>
  <button @click="counterStore.increment">{{ count }}</button>
  <br>
  <div>这是刚刚定义的doubleCount:{{ doubleCount }}</div>
</template>

App.vue

加上storeToRefs()

js 复制代码
<script setup>

import {useCounterStore} from '@/stores/counter'
//引入storeToRefs
import {storeToRefs} from "pinia";

const counterStore = useCounterStore()
//方法包裹(保持响应式更新)
const {count, doubleCount} =storeToRefs(useCounterStore()) 

</script>

<template>
  <button @click="counterStore.increment">{{ count }}</button>
  <br>
  <div>这是刚刚定义的doubleCount:{{ doubleCount }}</div>
</template>

数据正常响应

打印前后两次解构出来的值,使用过storeToRefs后解构出来的才是响应式的数据

注意:storeToRefs只负责数据的解构,方法无法通过其解构,如果要解构方法,只需要从原本的store对象中解构即可

js 复制代码
const {increment} =counterStore

5. 调试Pinia

总结

本文很简单的介绍了Pinia的使用,对于需要快速开发但又从未接触过Pinia的朋友极其友好,如果喜欢的话望收藏,点赞,有不足之处还望能够在评论区指出。

相关推荐
余生H20 分钟前
前端Python应用指南(二)深入Flask:理解Flask的应用结构与模块化设计
前端·后端·python·flask·全栈
outstanding木槿24 分钟前
JS中for循环里的ajax请求不数据
前端·javascript·react.js·ajax
酥饼~31 分钟前
html固定头和第一列简单例子
前端·javascript·html
一只不会编程的猫35 分钟前
高德地图自定义折线矢量图形
前端·vue.js·vue
m0_7482509337 分钟前
html 通用错误页面
前端·html
来吧~1 小时前
vue3使用video-player实现视频播放(可拖动视频窗口、调整大小)
前端·vue.js·音视频
魔术师卡颂1 小时前
最近看到太多 cursor 带来的焦虑,有些话想说
前端·aigc·openai
鎈卟誃筅甡1 小时前
Vuex 的使用和原理详解
前端·javascript
呆呆小雅1 小时前
二、创建第一个VUE项目
前端·javascript·vue.js
m0_748239331 小时前
前端(Ajax)
前端·javascript·ajax