Pinia

1/29/2024 Pinia

# Pinia

Pinia 是一个Vue.js 状态管理库。

# 一、定义 Store


Pinia 的 Store 是用 defineStore 方法定义的。 其参数需要给 Store 起个名字。

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    double: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})
1
2
3
4
5
6
7
8
9
10
11
  • state 是 store 的 数据
  • getters 是 store 的 计算属性
  • actions 则是 方法

# 二、使用 Store


虽然我们前面定义了一个 store,但在我们使用 <script setup> 调用 useStore()(或者使用 setup() 函数,像所有的组件那样 之前,store 实例是不会被创建的:

<script setup>
import { useCounterStore } from '@/stores/counter'
const store = useCounterStore()
</script>
1
2
3
4

# 三、State


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

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

# 访问 state​

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

const store = useStore()
store.count++
1
2

# 四、Getter


Getter 完全等同于 store 的 state 的计算值。可以通过 defineStore() 中的 getters 属性来定义它们。推荐使用箭头函数,并且它将接收 state 作为第一个参数:

export const useStore = defineStore('main', {
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
})
1
2
3
4
5
6
7
8

大多数时候,getter 仅依赖 state,不过,有时它们也可能会使用其他 getter 因此,即使在使用常规函数定义 getter 时,我们也可以通过 this 访问到 整个 store 实例

export const useStore = defineStore('main', {
  state: () => ({
    count: 0,
  }),
  getters: {
    // 自动推断出返回类型是一个 number
    doubleCount(state) {
      return state.count * 2
    },
    // 返回类型**必须**明确设置
    doublePlusOne(): number {
      // 整个 store 的 自动补全和类型标注 ✨
      return this.doubleCount + 1
    },
  },
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

与计算属性一样,你也可以组合多个 getter。通过 this,你可以访问到其他任何 getter

export const useStore = defineStore('main', {
  state: () => ({
    count: 0,
  }),
  getters: {
    // 类型是自动推断出来的,因为我们没有使用 `this`
    doubleCount: (state) => state.count * 2,
    doubleCountPlusOne() {
      return this.doubleCount + 1
    },
  },
})
1
2
3
4
5
6
7
8
9
10
11
12

# 五、Action


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

export const useCounterStore = defineStore('main', {
  state: () => ({
    count: 0,
  }),
  actions: {
    increment() {
      this.count++
    },
    randomizeCounter() {
      this.count = Math.round(100 * Math.random())
    },
  },
})
1
2
3
4
5
6
7
8
9
10
11
12
13

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

import { mande } from 'mande'

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

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

  actions: {
    async registerUser(login, password) {
      try {
        this.userData = await api.post({ login, password })
        showTooltip(`Welcome back ${this.userData.name}!`)
      } catch (error) {
        showTooltip(error)
        // 让表单组件显示错误
        return error
      }
    },
  },
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23