Pinia

Pinia

Pinia是Vue的专属的最新状态管理库,是Vuex状态管理工具的替代品,用于组件之间共享数据

Pinia中文文档

安装

  1. 下载依赖

    1
    npm install pinia
  2. 导入

    1
    2
    3
    4
    5
    6
    7
    8
    // main.js

    // 导入Pinia
    import { createPinia } from 'pinia'
    // 创建
    const pinia = createPinia()

    createApp(App).use(pinia).mount('#app')

Hello World

使用Pinia实现简易计数器

  1. 创建Store,定义变量和方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // stores.counter.js
    import { ref } from "vue";
    import { defineStore } from "pinia";

    export const useCounterStore = defineStore('counter', () => {
    const count = ref(0)
    function increment() {
    count.value++
    }

    return { count, increment }
    })
  2. 其他组件使用Store

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // components.PiniaTest.vue
    <script setup>
    import { useCounterStore } from '@/stores/counter'

    const counter = useCounterStore()
    </script>

    <template>
    <div>
    <button @click="counter.increment()">{{ counter.count }}</button>
    </div>
    </template>

Getter

相当于计算属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { computed, ref } from "vue";
import { defineStore } from "pinia";

export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function increment() {
count.value++
}
// Getter
const doubleCount = computed(() => count.value * 2)

return {
count,
increment,
doubleCount
}
})

Action

相当于方法

创建异步获取数据的action

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// store
import { ref } from "vue";
import { defineStore } from "pinia";
import axios from "axios";

const API_URL = 'http://geek.itheima.net/v1_0/channels'
export const useCounterStore = defineStore('counter', () => {
// Action
const list = ref([])
const getList = async () => {
const res = await axios.get(API_URL)
list.value = res.data.data.channels
}

return {
list,
getList
}
})

组件调用store的action

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script setup>
import { useCounterStore } from '@/stores/counter'
import { onMounted } from 'vue';

const counter = useCounterStore()

onMounted(() => {
counter.getList()
})
</script>

<template>
<ul>
<li v-for="item in counter.list" :key="item.id">
{{ item.name }}
</li>
</ul>
</template>

解构

可以通过storeToRefs把store解构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<script setup>
import { useCounterStore } from '@/stores/counter'
import { onMounted } from 'vue';
import { storeToRefs } from 'pinia'

const counter = useCounterStore()
// 只能解构出数据(state, getter),方法(action)解构不出来
const { list } = storeToRefs(counter)

onMounted(() => {
counter.getList()
})
</script>

<template>
<ul>
<li v-for="item in list" :key="item.id">
{{ item.name }}
</li>
</ul>
</template>

实例

通过pinia优化请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// src/store/category.js

import { ref } from "vue"
import { defineStore } from "pinia"
import { getCategoryAPI } from '@/apis/layout'

export const useCategoryStore = defineStore('categoryStore', () => {
// 导航列表
const categoryList = ref([])
// 获取导航列表
async function getCategoryList() {
const res = await getCategoryAPI()
categoryList.value = res.result
}

return {
categoryList,
getCategoryList
}
})

在父组件里发送请求,把数据保存在store中,之后子组件通过store获取数据,不需要再去重新请求数据

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
// src/views/Layout/index.vue

<script setup>
import LayoutNav from './components/LayoutNav.vue';
import LayoutHeader from './components/LayoutHeader.vue';
import LayoutFooter from './components/LayoutFooter.vue';
import LayoutFixed from './components/LayoutFixed.vue';
import { useCategoryStore } from '@/stores/category';
import { onMounted } from 'vue';

// 加载导航列表,让吸顶导航条和导航条只需要一次请求
const categoryStore = useCategoryStore()
onMounted(() => {
categoryStore.getCategoryList()
})

</script>

<template>
<LayoutFixed/>
<LayoutNav/>
<LayoutHeader/>
<RouterView/>
<LayoutFooter/>
</template>

pinia负责触发action

Pinia负责用户数据相关的state和action,组件中只负责触发action函数并传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// src/store/user.js
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { loginAPI } from '@/apis/user'

// 登录用户信息Store
export const useUserStore = defineStore('user', () => {
// 用户数据
const userInfo = ref({})
// 获取数据方法
async function getUserInfo({account, password}) {
const res = await loginAPI({ account, password })
userInfo.value = res.result
}
// 返回
return {
userInfo,
getUserInfo
}
})

组件通过调用useUserStore来发起请求,并把数据保存在Pinia。Pinia中的数据是保存在内存中的,一刷新就没了,需要进行持久化

Pinia持久化插件

持久化后,store return的数据会被保存到Local Storage


Pinia
http://xwww12.github.io/2023/05/10/前端/vue/Pinia/
作者
xw
发布于
2023年5月10日
许可协议