07-Pinia(V2)

7/24/2022

# 一,Pinia使用

  • Pinia(V2),是Vuex的下一版本,在Vue2和Vue3中都能用。
  • Pinia支持多store开发,可以非常自由地组织"状态管理"的数据流逻辑。
  • Pinia对Hooks编程思想非常友好,它对TS也非常友好。
  • 如果你想学习更多,去看官网和社区。

# 1,第一步:安装

yarn add pinia
yarn add axios@0.27.2
1
2

# 2,第二步:创建并在main.ts中使用

// src/pages/student/store/useCnodeStore.ts

import { defineStore } from 'pinia'
import axios from 'axios'

// 强调:pinia要求定义store时,名称以use*开头的函数
const useCnodeStore = defineStore('cnode', {
  // 这里的state,只能使用工厂函数写法
  // 特点:在组件中可以被共享,并且具有响应式
  state: () => {
    return {
      num: 1,
      list: []
    }
  },
  // 这里的getters就是计算属性,可用于计算state,还可以对另一个getters做计算
  getters: {
    total1 () {
      return this.num * 10
    },
    total2 () {
      return this.total1 * 2
    }
  },
  // 这里的actions,可以直接修改state数据,无论是同步代码,还是异步代码。
  actions: {
    addNum (step=1) {
      this.num += step
    },
    async getList (params) {
      const res = await axios({
        url: '/api/v1/topics',
        method: 'GET',
        params
      })
      if (res.status === 200) {
        if (res.data && res.data.success) {
          this.list = res.data.data
        }
      }
    }
  }
})

export default useCnodeStore
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// main.ts

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

let app = createApp(App)

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'

// 注册路由
app.use(router)
app.use(ElementPlus)

// 创建pinia实例,注册app.use(pinia)
const pinia = createPinia()
app.use(pinia)

app.mount('#app')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

在添加学生模块使用之,如下:

// src/pages/student/PageB.vue

<template>
  <h1>状态管理</h1>
  <h1 v-text="num"></h1>
  <h1 v-text="store.total1"></h1>
  <h1 v-text="store.total2"></h1>

  <button @click="add">自增</button>
  <button @click="reset">重置</button>
  <hr />

  <div v-for="(row, idx) in store.list" :key="row.id">
    <span v-text="idx"></span><span v-text="row.title"></span>
  </div>
  <button @click="pageHandle(-1)">上一页</button>
  <button @click="pageHandle(1)">下一页</button>
</template>

<script setup>
import useCnodeStore from "./store/useCnodeStore";
import { storeToRefs } from "pinia";
import { onMounted, watchEffect, ref } from "vue";
const page = ref(1);

// store属性解构后,响应式失效,用storeToRefs包一层
const { num } = storeToRefs(useCnodeStore());
// store属性不解构,响应式没有任何问题。
const store = useCnodeStore();
// console.log('---store', store)

const add = () => {
  // 修改pinia中的state数据【OK】
  // store.$patch({num: store.num + 1})

  // 使用actions方法修改pinia中的state数据
  store.addNum(10);
};

const reset = () => {
  store.$reset();
};

watchEffect(
  () => {
    store.getList({ page: page.value, limit: 5, tab: "ask" });
  },
  { flush: "pre" }
);

const pageHandle = (num) => {
  if (page.value === 1 && num === -1) return;
  page.value += num;
};

watchEffect(() => {
  // 监听store的变化
  store.$subscribe((mutations, state) => {
    // console.log('---mutations', mutations) // 信号
    // console.log('---state', state)  // store最新状态
    // todo something
  });
});

watchEffect(() => {
  // 用于计算actions方法的执行时间
  store.$onAction(({ name, after }) => {
    const st = Date.now();
    console.log(`${name} start`, st);
    after(() => {
      const et = Date.now();
      console.log(`${name} end`, et);
      console.log(`${name} 时间差`, et - st);
    });
  });
});
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

# 二,总结

  • createPinia() 用于创建pinia实例
  • defineStore('storeId', { state, getters, actions }) 会定义store, 每个store都一个以use*开头的Hooks函数, state必须是工厂函数, getters不仅可以对state进行计算, 还可以另一个getters进行计算, actions不仅可以编写同步方法, 还可以编写异步逻辑.
  • 怎么修改store中的state? 可以使用 $patch({})进行批量修改, 还可以调用actions方法来修改.
  • 怎么重置store中的state? 使用$reset() 方法重置store.
  • 如何监听store中的state的变化? 使用$subscribe((mutations, state)=>{})进行监听. 监听是一个副作用, 建议放在watchEffect中.
  • 如何测量actions方法的执行时间? 使用$onAction(({name, after})=>{})
  • 警告: 如果你对store进行解构, 响应式会失效, 使用 storeToRefs包裹一层即可.
Last Updated: 12/25/2022, 10:02:14 PM