pinia

Pinia

介绍

什么是 pinia

Vue 的状态管理库,会逐渐取代 Vuex

pinia 的优势

1.完全支持 ts

2.移除了 mutations,actions 同时支持同步和异步

3.轻量 压缩后体积只有 1kb 左右

4.没有模块嵌套,只有 store,每一个 store 都是独立的

5.store 一旦创建便会自动添加,无需手动添加 store

6.支持 vue2 与 vue3

使用

安装 pinia

1
npm install pinia --save

创建 store

新建 src/store 目录并在其下面创建 index.ts,导出 store

1
2
3
4
5
6
// src/store/index.ts
import {createPinia} from 'pinia'

const store = createPinia()

export default store

vue3 是 createPinia

vue2 是 PiniaVuePlugin

在 main.ts 中引入并使用。

1
2
3
4
5
6
7
8
9
10
11
12
// src/main.ts

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

const store = createPinia()
let app = createApp(App)

app.use(store)

app.mount('#app')

定义 store

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

import { defineStore } from 'pinia'

export const useTestStore = defineStore({
id: 'user', // id必填,唯一值(可以理解成命名空间)
state: () => { // vuex中的state是对象, pinia中是箭头函数返回对象
return {
name: 'lwj',
age: '23'
}
},
getters: {

},
actions: {

}
})

使用数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- src/App.vue -->
<template>
<div>
{{Test.name}}--{{Test.age}}
</div>
</template>

<script setup lang="ts">
import {useTestStore} from './store/index'
const Test = useTestStore()
</script>

<style scoped>

</style>

state

修改 state 的五种方法

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
<!-- src/App.vue -->
<template>
<div>
{{Test.name}}--{{Test.age}}
<button @click="change1">直接修改(修改一个)</button>
<button @click="change2">$patch对象写法(批量修改)</button>
<button @click="change3">$patch函数写法(可增加逻辑)</button>
<button @click="change4">$state(不常用 必须覆盖整个对象)</button>
<button @click="change5">actions</button>
</div>
</template>

<script setup lang="ts">
import {useTestStore} from './store/index'
const Test = useTestStore()

const change1 = () => {
Test.age++
}

const change2 = () => {
Test.$patch({
name: 'lwjjj',
age: 24
})
}

const change3 = () => {
Test.$patch((state) => {
state.name = 'lwjjjjjj',
state.age = 30
})
}

const change4 = () => {
Test.$state = {
name: 'lwjjjjjjjj',
age: 50
}
}

const change5 = () => {
Test.setCurrent(80)
}
</script>

<style scoped>

</style>
1
2
3
4
5
6
7
// 方法五需要在 src/store/index.ts 中配置 actions
actions: {
setCurrent(num:number) {
this.name = 'lwjjjjjjjjjjj'
this.age = num
}
}

解构

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
<template>
<div>origin value {{Test.name}}--{{Test.age}}}</div>
<div>
{{Test.name}}--{{Test.age}}
<button @click="change">change</button>
</div>
</template>

<script setup lang="ts">
import {useTestStore} from './store/index'
import { storeToRefs } from 'pinia';
const Test = useTestStore()

// pinia 解构不具有响应式(直接解构的话修改数据要.value,可以使用 storeToRefs 解决)
const {name, age} = storeToRefs(Test)

const change = () => {
Test.age++
console.log(name, age)
}
</script>

<style scoped>

</style>

actions 和 getters

使用

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
// src/store/index.ts
import { defineStore } from 'pinia'

type User = {
name: string,
age: number
}


const Login = (): Promise<User> => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
name: 'vincent',
age: 99
})
}, 2000);
})
}

export const useTestStore = defineStore({
id: 'user', // id必填,唯一值(可以理解成命名空间)
state: () => { // vuex中的state是对象, pinia中是箭头函数返回对象
return {
user: <User>{},
sex: "male"
}
},
getters: {
newName():string {
return `$~${this.sex}-${this.getUserAge}`
},
getUserAge():number {
return this.user.age
}
},
actions: {
async setUser() {
const result = await Login()
this.user = result
this.setName('female')
},
setName (sex:string) {
this.sex = sex
}
}
})

store 上的一些方法

$reset

重置 store 到他的初始状态

1
2
3
const reset = () => {
Test.$reset()
}

$subscribe

state 发生改变时触发

1
2
3
4
Test.$subscribe((args, state) => {
console.log(args)
console.log(state)
})

args

state

$onAction

监听 action 变化

1
2
3
Test.$onAction((args) => {
console.log(args)
})

args

插件

pinia 和 vuex 的通病:页面刷新状态会丢失(初始化)

写一个 pinia 插件缓存值(通过 localStorage)

写页面

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
<!-- App.vue -->
<template>
<p>{{Test.user}}</p>
<hr>
<p>{{Base.baseCurrent}}</p>
<hr>
<button @click="changeTest">changeTest</button>
<button @click="changeBase">changeBase</button>
</template>

<script setup lang="ts">
import {useTestStore, useStore} from './store/index'

const Test = useTestStore()
const Base = useStore()

const changeTest = () => {
Test.user.name = 'lwjjjjjjjjjjjjjjjjjjjjjjjjj'
Test.user.age = 100
}

const changeBase = () => {
Base.baseCurrent += 1
}
</script>

<style scoped>

</style>

写数据

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
// ./src/index.ts
import { defineStore } from 'pinia'

type User = {
name: string,
age: number
}

export const useTestStore = defineStore({
id: 'user', // id必填,唯一值(可以理解成命名空间)
state: () => { // vuex中的state是对象, pinia中是箭头函数返回对象
return {
user: <User>{},
sex: "male"
}
}
})

export const useStore = defineStore({
id: 'base',
state: () => {
return {
baseCurrent: 1
}
}
})

写插件(逻辑)

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
// main.ts
import { createApp, toRaw } from 'vue'
import App from './App.vue'
import {createPinia, PiniaPluginContext} from 'pinia'

type Options = {
key?:string
}

const __piniaKey__:string = 'xiaoman'

const setStorage = (key:string, value:any) => {
localStorage.setItem(key, JSON.stringify(value))
}

const getStorage = (key:string) => {
return localStorage.getItem(key) ? JSON.parse(localStorage.getItem(key) as string) : {}
}

const piniaPlugin = (options:Options) => {
return (context:PiniaPluginContext) => {
const {store} = context
const data = getStorage(`${options?.key ?? __piniaKey__}-${store.$id}`)
store.$subscribe(() => {
setStorage(`${options?.key ?? __piniaKey__}-${store.$id}`, toRaw(store.$state))
})
return {
...data
}
}
}

const store = createPinia()

store.use(piniaPlugin({
key: "pinia"
}))

let app = createApp(App)

app.use(store)

app.mount('#app')

pinia
http://example.com/2022/06/28/pinia/
Author
John Doe
Posted on
June 28, 2022
Licensed under