Pinia-状态管理

Pinia-状态管理

特点:

1. 轻量和模块化

  • Pinia 是一个轻量级的状态管理库,支持模块化管理,即可以将应用的状态分成多个 store 以实现更好的组织。
  • 使用 Pinia,可以定义多个 store,每个 store 都是一个独立的模块,负责管理其自己的状态、操作和计算属性(类似 Vuex 的模块化,但更加简单直观)。

2. 组合式 API 和逻辑隔离

  • Pinia 提供的 API 更符合 Vue 3 的组合式 API(Composition API)风格,状态管理逻辑与 Vue 3 的特性深度整合。
  • 通过组合式 API,使用起来更加灵活和直观,避免了在大型应用中常见的命名冲突问题。

3. 直观的持久化状态(支持 SSR)

  • Pinia 支持服务端渲染(SSR)和状态持久化,使得在服务端渲染应用中共享状态变得简单。
  • 使用 Pinia 时可以轻松地将 store 的状态持久化到本地存储中,以在页面刷新后保持数据。

4. 类型安全支持

  • 对于 TypeScript 用户来说,Pinia 提供了良好的类型推导和自动完成功能。它的 API 设计让类型支持更加顺畅,因此在写 TypeScript 项目时可以获得更好的开发体验。

5. 更简单的 API

  • Pinia 的 API 更简洁,移除了 Vuex 中的 mutation,直接使用 action 修改状态。这样可以减少心智负担,并且更加贴近 Vue 的设计哲学。
  • 没有像 Vuex 那样的 "commit" 或 "dispatch" 的复杂逻辑,Pinia 使用起来更加直观。

6. 热更新

  • Pinia 支持热更新(hot module replacement, HMR),使得在开发环境下对状态管理代码的修改可以直接生效,无需刷新页面。

定义Store

Store 是用 defineStore() 定义的,它的第一个参数要求是一个独一无二的名字:

js 复制代码
import { defineStore } from 'pinia'

// 你可以任意命名 `defineStore()` 的返回值,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。
// (比如 `useUserStore`,`useCartStore`,`useProductStore`)
// 第一个参数是你的应用中 Store 的唯一 ID。
export const useAlertsStore = defineStore('alerts', {
  // 其他配置...
})

这个名字 ,也被用作 id ,是必须传入的, Pinia 将用它来连接 store 和 devtools。为了养成习惯性的用法,将返回的函数命名为 use... 是一个符合组合式函数风格的约定。

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

Option Store

传入一个带有 stateactionsgetters 属性的 Option 对象

js 复制代码
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0, name: 'Eduardo' }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})

可以认为 state 是 store 的数据 (data),getters 是 store 的计算属性 (computed),而 actions 则是方法 (methods)。

Setup Store

与 Vue 组合式 API 的 setup 函数 相似,我们可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。

js 复制代码
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const doubleCount = computed(() => count.value * 2)
  function increment() {
    count.value++
  }

  return { count, doubleCount, increment }
})

使用Store

注意,store 是一个用 reactive 包装的对象,这意味着不需要在 getters 后面写 .value。就像 setup 中的 props 一样,我们不能对它进行解构

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

const store = useCounterStore()
// ❌ 这将不起作用,因为它破坏了响应性
// 这就和直接解构 `props` 一样
//const { name, doubleCount } = store
//name // 将始终是 "Eduardo"
//doubleCount // 将始终是 0
setTimeout(() => {
  store.increment()
}, 1000)
// ✅ 这样写是响应式的
// 💡 当然你也可以直接使用 `store.doubleCount`
const doubleValue = computed(() => store.doubleCount)
</script>

为了从 store 中提取属性时保持其响应性,你需要使用 storeToRefs()。它将为每一个响应式属性创建引用。当你只使用 store 的状态而不调用任何 action 时,它会非常有用。请注意,你可以直接从 store 中解构 action,因为它们也被绑定到 store 上:

js 复制代码
<script setup>
import { storeToRefs } from 'pinia'
const store = useCounterStore()
// `name` 和 `doubleCount` 是响应式的 ref
// 同时通过插件添加的属性也会被提取为 ref
// 并且会跳过所有的 action 或非响应式 (不是 ref 或 reactive) 的属性
const { name, doubleCount } = storeToRefs(store)
// 作为 action 的 increment 可以直接解构
const { increment } = store
</script>

State

在大多数情况下,state 都是你的 store 的核心。人们通常会先定义能代表他们 APP 的 state。在 Pinia 中,state 被定义为一个返回初始状态的函数。这使得 Pinia 可以同时支持服务端和客户端。

js 复制代码
import { defineStore } from 'pinia'

const useStore = defineStore('storeId', {
  // 为了完整类型推理,推荐使用箭头函数
  state: () => {
    return {
      // 所有这些属性都将自动推断出它们的类型
      count: 0,
      name: 'Eduardo',
      isAdmin: true,
      items: [],
      hasChanged: true,
    }
  },
})

访问 state

默认情况下,你可以通过 store 实例访问 state,直接对其进行读写。

js 复制代码
const store = useStore()

store.count++

注意,新的属性如果没有在 state() 中被定义 ,则不能被添加。它必须包含初始状态。例如:如果 secondCount 没有在 state() 中定义,我们无法执行 store.secondCount = 2

Getter

js 复制代码
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    // 自动推断出返回类型是一个 number
    doubleCount(state) {
      return state.count * 2
    },
    // 返回类型**必须**明确设置
    doublePlusOne(): number {
      // 整个 store 的 自动补全和类型标注 ✨
      return this.doubleCount + 1
    },
  },
})

用 computed函数 进行模拟

js 复制代码
//state
const count = ref(0)

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

Action

Action 相当于组件中的 method。它们可以通过 defineStore() 中的 actions 属性来定义,并且它们也是定义业务逻辑的完美选择。

js 复制代码
export const useCounterStore = defineStore('main', {
  state: () => ({
    count: 0,
  }),
  actions: {
    increment() {
      this.count++
    },
    randomizeCounter() {
      this.count = Math.round(100 * Math.random())
    },
  },
})

类似 getter,action 也可通过 this 访问整个 store 实例 ,并支持完整的类型标注(以及自动补全✨)不同的是,action 可以是异步的 ,你可以在它们里面 await 调用任何 API,以及其他 action!

setup写法:

Pinia持久化

官方文档:https://prazdevs.github.io/pinia-plugin-persistedstate/zh/

  1. 安装插件 pinia-plugin-persistedstate
jsx 复制代码
npm i pinia-plugin-persistedstate
  1. 使用 main.js
jsx 复制代码
import persist from 'pinia-plugin-persistedstate'
...
app.use(createPinia().use(persist))
  1. 配置 store/counter.js
jsx 复制代码
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'

export const useCounterStore = defineStore('counter', () => {
  ...
  return {
    count,
    doubleCount,
    increment
  }
}, {
  persist: true
})
相关推荐
请叫我欧皇i18 分钟前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
533_20 分钟前
[vue] 深拷贝 lodash cloneDeep
前端·javascript·vue.js
guokanglun26 分钟前
空间数据存储格式GeoJSON
前端
zhang-zan1 小时前
nodejs操作selenium-webdriver
前端·javascript·selenium
ZBY520311 小时前
【Vue】 npm install amap-js-api-loader指南
javascript·vue.js·npm
猫爪笔记1 小时前
前端:HTML (学习笔记)【2】
前端·笔记·学习·html
brief of gali1 小时前
记录一个奇怪的前端布局现象
前端
计算机毕设指导61 小时前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
Json_181790144802 小时前
电商拍立淘按图搜索API接口系列,文档说明参考
前端·数据库
风尚云网3 小时前
风尚云网前端学习:一个简易前端新手友好的HTML5页面布局与样式设计
前端·css·学习·html·html5·风尚云网