随着vue的更新,vuex已经更新到了vuex5的版本,此时我们意识到Pinia已经实现了vuex5中想要的大部分内容,因此决定实现Pinia取代vuex。与vuex相比,Pinia提供了一个更简单的API,具有更少的规范,提供了Composition-API的风格,最重要是在于TypeScrpit一起使用时具有可靠的类型推断支持。
Pinia API 与 Vuex ≤4 有很大不同,即:
在main.ts 中设置
import { createPinia } from 'pinia'
const app = createApp(App)
app.use(createPinia())
app.mount('#app')
import {defineStore} from 'pinia';
// 第一个参数是引用成俗中store的唯一id
export const useStore = defineStore('main', {
// other opition ...
})
import {useStore} from '@/stores'
const store = useStore();
console.log(store); // store可在实例模板中使用
// 注意:store不支持解构写法,否则会失去响应式
// 如果想从store中提取出属性相同的数据并保持响应式,则需要使用storeToRefs()或者使用toRefs()
import { storeToRefs } from 'pinia';
const store = useStore();
const { name, doubleCount } = storeToRefs(store);
console.log(name, doubleCount);
state是vue存储库的中心,可以时间跨页面多组件之间的数据共享
①组合式api(Setup Stores)
写法介绍:
// 定义组合式api的pinia数据
export const useCounterStore = defineStore('counter', () => {
// state数据
const count = ref(0)
const name = ref('Eduardo')
// getters计算属性
const doubleCount = computed(() => count.value * 2)
// action函数方法
function increment() {
count.value++
}
return { count, name, doubleCount, increment }
})
// 使用组合式api的pinia
import {useCounterStore} from '@/stores/counter'
const conter = useCounterStore()
数字:{{conter.count}}
姓名:{{conter.name}}
二倍:{{conter.doubleCount}}
②选项式api(Option Stores)
写法介绍:
export const useCounterStore = defineStore('counter', {
// state数据
state: () => ({ count: 0, name: 'Eduardo' }),
// getters计算属性
getters: {
doubleCount: (state) => state.count * 2,
},
// action函数方法
actions: {
increment() {
this.count++
},
},
})
①$patch的使用场景
当需要同时修改多个state属性时,可以使用$patch
方法
import useStore from '@/stores'
const store = useStore()
store.$patch({
count: store.count + 1,
age: 12,
name: 'DIO'
})
②$patch的函数参数用法
import useStore from '@/stores'
const cartStore = useStore()
cartStore.$patch((state) => {
state.items.push({ name: 'shoes', quantity: 1 })
state.hasChanged = true
})
③替换state
store.$state = { count: 24 }
store.$patch({ count: 24 })
选项式api下state的重置:
store.$reset()
组合式api下state的重置:
setup api下不能使用 $reset 方法
会报错: Store "xxx" is built using the setup syntax and does not implement $reset()
需要在main.ts文件中给pinia设置$reset
import { createPinia } from 'pinia'
const app = createApp(App)
const pinia = createPinia();
pinia.use(({ store }) => {
const initialState = JSON.parse(JSON.stringify(store.$state))
store.$reset = () => {
store.$state = JSON.parse(JSON.stringify(initialState))
}
})
app.use(pinia)
import useStore from '@/stores'
const store = useStore()
store.$subscribe((mutation, state) => {
// mutation:是记录state变化信息的对象
// state:是store的state对象
console.log(mutation, state)
// import { MutationType } from 'pinia'
mutation.type // 'direct' | 'patch object' | 'patch function'
// 与 cartStore.$id 相同,
mutation.storeId // 'cart'
// 仅适用于 mutation.type === 'patch object'
mutation.payload // 补丁对象传递给 to cartStore.$patch()
// 每当它发生变化时,将整个状态持久化到本地存储
localStorage.setItem('cart', JSON.stringify(state))
})
注意事项:
$subscribe() 与 watch()的区别
$subscribe是$patch执行就会触发(无论值是否真的改变了),而watch是监听对象(值)改变才会触发。
getters
可以理解为store
中state
的计算属性
采用setup aoi的形式(组合式api)
定义:
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const userStore = defineStore('user', () => {
const nick = ref('小明');
const codes = ref([80]);
// 此处即为getters
const msg = computed(() => {
return '昵称:' + nick.value + ', 得分:' + codes.value
})
return { nick, codes, msg }
})
使用:
import { userStore } from '@/stores/user';
import { toRefs } from 'vue';
const user = userStore()
const { nick, codes, msg } = toRefs(user);
{{msg}} // 此处为 pinia中的msg信息
actions
可以理解为store
中的methods
(也就是函数)
采用setup aoi的形式(组合式api)
定义:
import { ref } from 'vue'
import { defineStore } from 'pinia'
export const userStore = defineStore('user', () => {
const codes = ref(58);
// 定义actions
function renderCode () {
codes.value = Math.floor(Math.random() * 100)
}
return { codes, renderCode }
})
使用:
import { userStore } from '@/stores/user';
import { toRefs } from 'vue'
const { renderCode } = toRefs(userStore());
import { createPinia } from 'pinia'
// 为安装此插件后创建的每个store添加一个名为 `secret` 的属性
// 这可能在不同的文件中
function SecretPiniaPlugin() {
return { secret: 'the cake is a lie' }
}
const pinia = createPinia()
// 将插件提供给 pinia
pinia.use(SecretPiniaPlugin)
// 在另一个文件中
const store = useStore()
store.secret // 'the cake is a lie'
采用插件
pinia-plugin-persistedstate:pinia-plugin-persistedstate - npm (npmjs.com)
使用:
main.ts
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate)
app.use(pinia)
具体的stores.ts文件
方法一:
直接设置 `persist: true` 即可
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const userStore = defineStore('user', () => {
const nick = ref('小明');
const codes = ref(58);
const msg = computed(() => {
return '昵称:' + nick.value + ', 得分:' + codes.value
})
const moreMsg = computed(() => {
return msg.value + ' | ' + (codes.value >= 60 ? '合格' : '不合格')
})
function renderCode() {
codes.value = Math.floor(Math.random() * 100)
}
return { nick, codes, msg, moreMsg, renderCode }
}, {
persist: true
})
方法二:
具体设置
import { defineStore } from 'pinia'
export const useStore = defineStore('store',() => {
const nick = ref('小明');
const codes = ref(58);
return { nick, codes }
}, {
persist: {
storage: sessionStorage, // 设置存储位置,sessionStorage浏览器关闭就会清空,默认是localStorage
paths: ['someState'], // 需要持久话存储的数据
},
})