vlambda博客
学习文章列表

vue3使用pinia管理状态

Pinia

pinia 是一款新的vue3的状态管理库,完整的typescript支持。

安装

yarn add pinia
# or npm
npm install pinia

创建根store并且引用到app上

import { createPinia } from 'pinia'

app.use(createPinia())

定义Store

使用defineStore定义store,第一个参数必须是全局唯一的id,可以使用Symbol

import { defineStore } from 'pinia'

// 第一个参数必须是全局唯一
export const useStore = defineStore('main', {

})

使用store

setup中使用useStore创建store实例

<script setup>
import {useStore} from '@/stores/counter'

const store = useStore()

....
</script>

状态State

定义状态

import { defineStore } from 'pinia',

const useCounterStore = defineStore('counterStore', {
  state: () => ({
    counter: 0
  })
})

定义强状态

import { defineStore } from 'pinia',

interface ICounterStoreState{
  counter: number
}

const useCounterStore = defineStore('counterStore', {
  state: ():ICounterStoreState => ({
    counter0
  })
})

使用和重置状态

const store = useCounterStore()

// 使用
store.counter++

// 重置
store.$reset()

改变状态

store.$patch({
  counter: store.counter + 1,
  name: 'Abalam',
})

替换状态

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

计算属性Getters

Getter 完全等同于 Store 状态的计算值,可以用 defineStore() 中的 getters 属性定义

export const useStore = defineStore('main', {
  state: () => ({
    counter: 0,
  }),
  getters: {
    doubleCount: (state) => state.counter * 2,
  },
})

传递参数到getters

Getter 是计算属性,也可叫只读属性,因此不可能将任何参数传递给它们。但是可以从 getter 返回一个函数以接受任何参数

export const useStore = defineStore('main', {
  getters: {
    getUserById(state) => {
      return (userId) => state.users.find((user) => user.id === userId)
    },
  },
})

访问其他store的getters

import { useOtherStore } from './other-store'

export const useStore = defineStore('main', {
  state() => ({
    // ...
  }),
  getters: {
    otherGetter(state) {
      const otherStore = useOtherStore()
      return state.localData + otherStore.data
    },
  },
})

动作Actions

动作相当于组件中的方法,可以使用 defineStore() 中的 actions 属性来定义,它们非常适合定义业务逻辑

import { mande } from 'mande'

const api = mande('/api/users')

export const useUsers = defineStore('users', {
  state() => ({
    userDatanull,
    // ...
  }),

  actions: {
    async registerUser(login, password) {
      try {
        this.userData = await api.post({ login, password })
        showTooltip(`Welcome back ${this.userData.name}!`)
      } catch (error) {
        showTooltip(error)
        // let the form component display the error
        return error
      }
    },
  },
})

访问其他store的actions

import { useAuthStore } from './auth-store'

export const useSettingsStore = defineStore('settings', {
  state() => ({
    preferencesnull,
    // ...
  }),
  actions: {
    async fetchUserPreferences() {
      const auth = useAuthStore()
      if (auth.isAuthenticated) {
        this.preferences = await fetchPreferences()
      } else {
        throw new Error('User must be authenticated')
      }
    },
  },
})

插件

假设需要在stroe中使用router,就需要使用到pinia的插件机制扩展store的api

pinia.d.ts

import 'pinia'

import { Router} from 'vue-router'

declare module 'pinia' {
  export interface PiniaCustomProperties {
    $router: Router,
  }
}

定义插件

import { createPinia } from 'pinia'
import { App} from "vue";

import { router } from '@/routers'

const pinia = createPinia()
pinia.use(({ store }) => {
    store.$router = router
  })
app.use(pinia)

在action中使用插件定义的pai

import { defineStore } from 'pinia'
import { RouteLocationNormalized } from 'vue-router'
export const useApplicationStore = defineStore('application', {
  state: () => (
    ...
  ),
  actions:{
    toHome(){
      this.$router.push('/home')
    }
  }
})

推荐结构

stores

index.ts
use.store.ts
app.store.ts    …

stores/index.ts

import { createPinia } from 'pinia'
import { App} from "vue";

const pinia = createPinia()

export function setupPinia(app: App){
    pinia.use(({ store }) => {
        ... 这里安装插件
      })
    app.use(pinia)
}

export * from './use.store.ts'
export * from './app.store.ts'

何时使用状态管理器

全局都会使用到的状态使用状态管理器,比如用户信息、主题、权限等等