一起读pinia官方文档

pinia简述

参考文献:
官方文档

spa

spa回顾

概念:就是只有一张Web页面的应用。单页面程序SPA是加载单个HTML页面并在用户与应用程序交互时动态更新页面的Web应用程序
在这里插入图片描述

spa引入pinia

npm install pinia

//main.js或main.ts中
import { createApp } from 'vue'
import {createPinia} from "pinia"
createApp(App).use(new createPinia()).mount('#app')

引言

在vue3中,其实最简单、最简洁的状态管理不是vuex,也不是pinia,是单个reactive函数导出

import { ref } from"vue";
export const state = ref(false)

这样就在不同组件进行共同使用状态,并且具有响应式的效果(同理,对象可以用reactiva进行包裹)
但是这样会让程序陷入安全漏洞

基本使用

创建相关文件夹store,其中有文件index进行状导出
整体目录树结构如下:
在这里插入图片描述
index.js文件中:

import { defineStore } from "pinia";
//定义一个简单的状态,action就是其中内部封装的方法,有利于操控store
//注意,这样直接使用的Store具有响应式
export const useCountStore=defineStore("couter",{
  state:()=>{
    return {count:0}
  },
  actions:{
    //表示增加的操作,状态值进行改变:
    imcrement(){
      this.count++
    },
    //表示改变数量的操作,状态值也同样会改变:
   changeCount(count){
     this.count=count;
   }
  }
}

App.vue文件中的script层

//在.vue文件中渲染
<script setup>
import {useCountStore} from './stores/index'
const counter=useCountStore()
function changeState(){
   //第一种:通过store中的函数改变store中的值
  // counter.imcrement()
  //第二种:直接++改变store中的值
  counter.count++
  counter.changeCount(100)
}
const count=counter.count
</script>

<template>
<!--注意:当元素没有结构赋值前-->
 <div>this is fater compoment:{{counter.count}}</div>
 <button @click="changeState">改变状态</button>
</template>

上一组案例只是最简单的
下面来一个比较充分的应用:
1.查看state的值:state中可以有各种类型的值,对象,字符、数值,对象同样也可以是各种类型组成
2. getter不是一个方法,是属性,使用的时候调用方法,返回相关的值,为了避免直接操作this,方法会传入此时的状态state,但是,函数中都能操作state和this,让this发生响应式的改变
3.

export const todos = defineStore('todos', {
  state: () => ({
    /** @type {{ text: string, id: number, isFinished: boolean }[]} */
    todos: [],
    /** @type {'all' | 'finished' | 'unfinished'} */
    filter: 'all',
    // type 会自动推断为 number
    nextId: 0,
  }),
  getters: {
    //操作state,不用this改变状态
    //getter不是一个方法,是属性,使用的时候调用方法,返回相关的值
    //本质是内部计算值
    finishedTodos(state) {
      // 自动完成! ✨
      以下两种都会改变用户状态
      //this.filter="666"
      state.filter="666"
      return state.todos.filter((todo) => todo.isFinished)
    },
    unfinishedTodos(state) {
      return state.todos.filter((todo) => !todo.isFinished)
    },
    /**
    * @returns {{ text: string, id: number, isFinished: boolean }[]}
    */
    //getter方法相互调用
    filteredTodos(state) {
      if (this.filter === 'finished') {
        // 自动调用其他 getter ✨
        return this.finishedTodos
      } else if (this.filter === 'unfinished') {
        return this.unfinishedTodos
      }
      return this.todos
    },
  },
  actions: {
    // 任何数量的参数,返回一个 Promise 或者不返回
    //这里和gettes就有区别了
    //getter是返回了目标对象或者值
    //提供一个函数封装状态,
    addTodo(text) {
      // 你可以直接改变状态
      this.todos.push({ text, id: this.nextId++, isFinished: false })
    },
  },
})
调用相关方法后返回的值,影响用户状态

State状态(类比data)

对象

const counter=useCountStore()

经过这一步得到的counter是一个proxy对象,其中的count属性就是一个ObjRefImpl对象

基本操作

const store = useStore()
//访问
store.counter++
//重置
store.$reset()
//修改
//A计划
//不推荐这一种,因为这一种还需要让代码内部自己判断有哪里进行了更新
store.$patch({
  counter: store.counter + 1,
  name: 'Abalam',
})
//B计划
//往状态里面进行针对性修改
cartStore.$patch((state) => {
  state.items.push({ name: 'shoes', quantity: 1 })
  state.hasChanged = true
})

//替换state
store.$state = { counter: 666, name: 'Paimon' }

App.vue中进行展示

<template>
<div>this is fater compoment:{{double}},{{magicValue}}</div>
<button @click="changeState">改变状态</button>
</template>

代码中的this
在这里插入图片描述

代码中的store
在这里插入图片描述

响应式

store 是一个用reactive 包裹的对象,这意味着不需要在getter 之后写.value,但是,就像setup 中的props 一样,我们不能对其进行解构:

export default defineComponent({
  setup() {
    const store = useStore()
    // ❌ 这不起作用,因为它会破坏响应式
    // 这和从 props 解构是一样的
    const { name, doubleCount } = store
    
    name // "eduardo"
    doubleCount // 2
    
    return {
      // 一直会是 "eduardo"
      name,
      // 一直会是 2
      doubleCount,
      // 这将是响应式的
      doubleValue: computed(() => store.doubleCount),
    }
  },
})

为了从 Store 中提取属性同时保持其响应式,您需要使用storeToRefs()。 它将为任何响应式属性创建 refs。 当您仅使用 store 中的状态但不调用任何操作时,这很有用:

import { storeToRefs } from 'pinia'

export default defineComponent({
  setup() {
    const store = useStore()
    // `name` 和 `doubleCount` 是响应式引用
    // 这也会为插件添加的属性创建引用
    // 但跳过任何 action 或 非响应式(不是 ref/reactive)的属性
    const { name, doubleCount } = storeToRefs(store)
    
    return {
      name,
      doubleCount
    }
  },
})

订阅机制

当监听的时候进行打印,与常规的 watch() 相比,使用 $subscribe() 的优点是 subscriptions 只会在 patches 之后触发一次(摘自官方文档)。

<!--App.vue-->
<template>
    <div>{{state.count}}</div>
    <Son></Son>
</template>
<script setup>
import {useCountStore} from './stores/index'
import Son from './components/Son.vue';
const state=useCountStore()
state.$subscribe((mutation, state) => {
        console.log(Object.prototype.toString(mutation));
        console.log(mutation);
</script>

<!--Son.vue-->
<template>
    <div>this is son component</div>
    <div>son:{{counter.count}}</div>
    <button @click="addCount">+</button>
</template>
<script setup>
import {useCountStore} from '../stores/index'
name:"Son"
const counter=useCountStore()
function addCount(){
    counter.count++
}
    
</script>

订阅函数中传入了2个函数,将他们打印一下,第二个就是我们熟悉的state,而第一个就是mutation,将他打印如图所示,可以知道他的基本结构。
这里知乎还有一个问题值得一看:为什么Pinia不需要mutation了,是怎么实现的?
在这里插入图片描述

Getters(计算值)

指定getter返回的值类型

export const useStore = defineStore('main', {
  state: () => ({
    counter: 0,
  }),
  getters: {
    // 自动将返回类型推断为数字
    doubleCount(state) {
      return state.counter * 2
    },
    // 返回类型必须明确设置
    doublePlusOne(): number {
      return this.counter * 2 + 1
    },
  },
})

访问getters中进行缓存

如下面规划了数组并且进行操作,最终返回数组操作的结果
在这里插入图片描述

访问其他的store

在getters定义相关对象并进行访问
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值