uniapp+vue3 setup+ts 开发小程序实战(状态管理篇) 2022-0-灵析社区

前端码农


Pinia是什么

Pinia是vue团队推荐的下一代状态管理方案,相比之前的vuex方案,Pinia具有以下特点:

  1. 配合vue3 Componsition API写法,更可靠的TypeScript 类型推断支持
  2. Pinia 没有 Mutations,可以直接修改state数据,Actions 支持同步和异步
  3. 提供扁平结构,没有模块的嵌套结构等

安装依赖

npm i pinia -S

接着src目录下创建stores文件夹(注意:这里用复数形式命名以强调pinia的多状态实例的特性,也就是上面提到的特点3)

初始化工作

创建index.ts文件:

stores文件夹下新建index.ts:

import { createPinia } from 'pinia'
const pinia = createPinia()

export default pinia

在main.ts中引用:

import { createSSRApp } from 'vue'
import App from './App.vue'
import pinia from './store'

export function createApp() {
  const app = createSSRApp(App)
  app.use(pinia)
  return {
    app,
  }
}

以上就完成了初始化工作,下面我们定义一个user模块说明如何使用

定义user模块

在stores目录下新建user文件夹,在其目录下我们新建两个文件:index.ts和types.ts(管理数据结构)

index.ts:

import { defineStore } from 'pinia'
import { RootState } from './types'

export const useUserStore = defineStore('user', {
  state: (): RootState => ({
    userInfo: {},
    token: '',
  }),
  getters: {
    // 示例返回大写字符
    capName(state) {
      return state.userInfo.name.toUpperCase()
    },
  },
  actions: {
    async setUserInfo() {
      // 这里可以发起请求
      const userInfo = await getUserInfo()
      this.userInfo = userInfo
    },
  },
})
  • defineStore方法第一个参数“user”是模块的名称,值必须是唯一的(多个模块不能重名)
  • state:箭头函数,返回一个对象数据
  • getters:可以理解为计算属性,对state中的数据做进一步计算处理
  • actions:封装业务逻辑,同步/异步修改state数据

值得一提的是,对于store模块命名写法,有个约定俗成的写法:使用“use”+ 功能模块名称,如上面的useUserStore

页面中使用

<template>
  <view>{userStore.userInfo.name}</view>  
</template>

<script setup lang="ts">
  import { useUserStore } from '@/stores/user'

  const userStore = useUserStore()
  console.log(userStore.userInfo)
  
</script>

解构state

如果要使用解构写法获取值,而又不丢失响应式,我们需要用到storeToRefs方法

const { userInfo } = storeToRefs(userStore)
userInfo.value.name = 'username'

修改state

  • 直接修改:userStore.userInfo = {}
  • $patch批量修改(性能更好):
// $patch有两种写法

// 传入对象:适合同时修改多个不复杂的数据
store.$patch({
  userInfo: {},
  token: '',
})

// 传入函数写法:上面传入对象写法在遇到复杂数据时,成本很高
//(例如,从数组中推送、删除、拼接元素)都需要创建一个新集合,这时就可以传入一个函数
cartStore.$patch((state) => {
  state.items.push({ name: 'shoes', quantity: 1 })
  state.hasChanged = true
})
  • $reset恢复初始值:例如我们在state中定义一个userInfo初始值
userInfo: {
  name: '默认用户名',
  avatar: '默认用户头像'
}

假设用户登录后我们修改了上面的用户信息,退出登录时,我们可以直接调用userStore.$reset()恢复初始值。不过要注意的是,它恢复的是整个state值,并不能只恢复state下面的单个值。对此,我们可以将有恢复初始值的需求的变量,用一个变量存储然后在需要恢复时,可以在action中定义一个方法重新赋值即可。

监听状态

如果你需要监听状态做一些处理,例如将数据持久化到本地,可以使用$subscribe()方法。

userStore.$subscribe((mutations, state) => {
  uni.setStorageSync('userInfo', state.userInfo)
})

数据持久化插件:pinia-plugin-persistedstate

在只需要本地存储一小部分字段时,可以通过上面监听状态钩子简易实现。但如果需要存储大量数据字段,则可以使用与之搭配的插件:pinia-plugin-persistedstate

安装

npm i pinia-plugin-persistedstate

修改stores/index.ts

import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

export default pinia

user模块

export const useUserStore = defineStore('user', {
  state: (): RootState => ({
    userInfo: {
      id: null,
      name: '',
    },
    token: '',
    userName: '',
  }),
  persist: {
    key: 'store-key', // 本地存储key
    storage: {
      setItem: uni.setStorageSync,
      getItem: uni.getStorageSync,
    },
  },
  actions: {
    setName(name: string) {
      this.userName = name
    },
  },
})

打开微信开发者工具可以看到:


可以看到上面存储的是整个user模块的state数据,如果只需要存储state下的某些字段,可以这么写:

  persist: {
    key: 'store-key',
    paths: ['userInfo.name'],
    storage: {
      setItem: uni.setStorageSync,
      getItem: uni.getStorageSync,
    },
  }

微信开发工具中显示如下:

总结

至此,已经完成了pinia状态管理使用及配合pinia-plugin-persistedstate插件实现数据本地存储,接下来请移步《网络请求封装篇》。



阅读量:2028

点赞量:0

收藏量:0