Pinia
介绍
什么是 pinia
Vue 的状态管理库,会逐渐取代 Vuex
pinia 的优势
1.完全支持 ts
2.移除了 mutations,actions 同时支持同步和异步
3.轻量 压缩后体积只有 1kb 左右
4.没有模块嵌套,只有 store,每一个 store 都是独立的
5.store 一旦创建便会自动添加,无需手动添加 store
6.支持 vue2 与 vue3
使用
安装 pinia
创建 store
新建 src/store 目录并在其下面创建 index.ts,导出 store
1 2 3 4 5 6
| 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
|
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
|
import { defineStore } from 'pinia'
export const useTestStore = defineStore({ id: 'user', state: () => { 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
| 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
| 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', state: () => { 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
| import { defineStore } from 'pinia'
type User = { name: string, age: number }
export const useTestStore = defineStore({ id: 'user', state: () => { 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
| 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')
|