Vue笔记--状态管理

这一节了解一下Vue3中的状态管理,在Vue中,Pinia是官方推荐的状态管理库,它是一个专为Vue设计的轻量级、类型安全的状态管理库。它允许开发者跨组件、跨页面共享和管理全局状态,简单总结如下:

API:

1 createPinia():创建Pinia根实例,类似Vuex的Store根,注册到Vue app中
2 defineStore(id, options)定义仓库store,id是仓库唯一标识;定义state、getters、actions
3 state 状态:存储共享响应式数据(相当于组件`data()`)
4 getters 计算属性:基于 state 派生数据,缓存结果,类似组件computed
5 actions 方法:修改state的函数,支持同步、异步请求;Pinia没有mutation,直接改state或在actions修改
6 state 直接替换整个store状态对象
7 reset() 将state重置回初始默认值
8 patch() 批量修改 state,可以传对象/函数,减少多次响应式更新
9 subscribe() 订阅state变化,state 改动自动触发回调
10 storeToRefs() 从store解构数据保持响应式;直接解构会丢失响应,必须用该API

场景:

1 跨组件/跨页面共享状态

2 需要状态持久化的应用

3 TypeScript项目

栗子:

javascript 复制代码
main.js注 pinia

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

const app = createApp(App)
const pinia = createPinia()
app.use(pinia)
app.mount('#app')
javascript 复制代码
stores/counter.js定义store

import { defineStore } from 'pinia'

// id:"counter" 唯一仓库标识
export const useCounterStore = defineStore('counter', {
  // state:共享状态
  state() {
    return {
      count: 0,
      userName: "张三"
    }
  },

  getters: {
    doubleCount(state) {
      return state.count * 2
    }
  },

  actions: {
    increment() {
      // 直接修改state,不需要mutation
      this.count++
    },
    decrement() {
      this.count--
    },
    resetCount() {
      this.$reset() //重置state到初始值
    }
  }
})
javascript 复制代码
App.vue使用store

<template>
  <div>
    <h3>Pinia计数器Demo</h3>
    <p>count:{{ counterStore.count }}</p>
    <p>doubleCount(getter):{{ counterStore.doubleCount }}</p>
    <p>用户名:{{ counterStore.userName }}</p>
    <button @click="counterStore.increment">+1</button>
    <button @click="counterStore.decrement">-1</button>
    <button @click="counterStore.resetCount">重置</button>

    <h4>storeToRefs解构</h4>
    <p>解构count: {{ count }}</p>
    <button @click="count++">直接修改解构后的count</button>
  </div>
</template>

<script setup>
import { useCounterStore } from './stores/counter'
import { storeToRefs } from 'pinia'

const counterStore = useCounterStore()
const { count } = storeToRefs(counterStore)
</script>

Demo2

javascript 复制代码
stores/user.js

import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state() {
    return {
      token: "",
      isLogin: false,
      userId: null,
      nickName: ""
    }
  },
  getters: {
    isTokenValid(state) {
      return !!state.token
    }
  },
  actions: {
    async login(username, password) {
      await new Promise(resolve => setTimeout(resolve, 800))
      if(username === "admin" && password === "123456"){
        this.$patch({
          token: "mock-token-0001",
          isLogin: true,
          userId: 1001,
          nickName: "管理员"
        })
      }else{
        throw new Error("账号密码错误")
      }
    },
    logout() {
      this.$reset()
    }
  }
})
javascript 复制代码
App.vue

<template>
  <div>
    <h3>Pinia异步登录Demo</h3>
    <div>
      <input v-model="username" placeholder="用户名admin" />
      <input v-model="password" placeholder="密码123456" type="password"/>
      <button @click="handleLogin" :disabled="loading">登录</button>
      <button @click="userStore.logout">退出登录</button>
    </div>

    <div v-if="userStore.isLogin">
      <p>登录成功!</p>
      <p>nickName:{{ userStore.nickName }}</p>
      <p>token:{{ userStore.token }}</p>
      <p>token有效(getter): {{ userStore.isTokenValid }}</p>
    </div>
    <p v-if="errMsg" style="color:red">{{ errMsg }}</p>
  </div>
</template>

<script setup>
import { ref } from "vue"
import { useUserStore } from "./stores/user"

const userStore = useUserStore()
const username = ref("")
const password = ref("")
const loading = ref(false)
const errMsg = ref("")

userStore.$subscribe((mutation, state) => {
  console.log("state发生变更:", state)
})

const handleLogin = async ()=>{
  loading.value = true
  errMsg.value = ""
  try {
    await userStore.login(username.value, password.value)
  } catch(e) {
    errMsg.value = e.message
  } finally {
    loading.value = false
  }
}
</script>

注意:

1 解构必须使用storeToRefs

2 Store之间避免循环依赖

相关推荐
Larru-Sun1 小时前
Nginx + Vue Router 基础:SPA History 部署、反向代理与请求分流
运维·vue.js·nginx
John_ToDebug9 小时前
判断力无法被 AI 替代,但它正在被你亲手扔掉
经验分享·笔记
benbenAItalk9 小时前
数字人口播视频的批量生产实践:素材规范、任务编排与质量验收
java·前端·音视频
2601_9628857210 小时前
如何用 Python 扫描 A 股跳空缺口并统计缺口回补概率?
java·前端·python
西瓜太郎123410 小时前
Claude Code、Codex CLI、Gemini CLI 能否共用一枚 Key?先看协议选择矩阵
前端·api 网关·claude code·gemini cli·codex cli
柳鲲鹏10 小时前
运气学概论:提纲草案
笔记
陈随易12 小时前
在Finch用了62亿词元,我认为这是新一代Agent工具之神
前端·人工智能·后端
水域安全老周12 小时前
水趣钓鱼救生衣专利拆解:两级锁紧如何解决落水人衣分离
java·前端·网络
疯狂打码的少年13 小时前
【计算机网络】子网掩码与子网划分计算(含CIDR表示法)
服务器·笔记·计算机网络·php