点击在线浏览,体验更好链接
古代JavaScript高级小册链接
深入浅出Dart链接
古代TypeScript高级小册链接
linwu的算法笔记链接

Pinia 是 Vue.js 官网举荐的新一代状态治理库,它提供了十分简洁和直观的 API,能够极大地提高咱们治理利用状态的效率。本文将深刻介绍 Pinia 的各种高级用法,内容涵盖:

Pinia 的劣势

相比 Vuex,Pinia 有以下长处:

  • 更贴合 Vue 3 的 Composition API 格调,学习老本更低
  • 不须要辨别 Mutation 和 Action,对立应用 Actions 操作状态
  • 反对 TypeScript,能够充分利用 TS 的动态类型零碎
  • 模块化治理 States,每个模块是一个 Store
  • 直观的 Devtools,能够看到每个 State 的变动

创立 Pinia

在 main.js 中导入 createPinia 并应用:

import { createApp } from 'vue'import { createPinia } from 'pinia'const pinia = createPinia()const app = createApp(App)app.use(pinia)

能够通过 app.config.globalProperties.$pinia 拜访 Pinia 实例。

Option Store

与 Vue 的选项式 API 相似,咱们也能够传入一个带有 stateactions 与 getters 属性的 Option 对象(废除了Mutations)

应用 defineStore API 定义 Store:

import { defineStore } from 'pinia'export const useMainStore = defineStore('main', {  // state  state: () => {    return {      counter: 0    }  },  // getters  getters: {    doubleCount(state) {      return state.counter * 2    }  },  // actions  actions: {    increment() {      this.counter++     }  }})
  • 接管惟一 ID 作为第一个参数
  • state、getters、actions 定义形式与 Vue 组件相似
  • 能够间接通过 this 拜访状态

Pinia 提供多种选项配置 Store:

state

定义响应式状态:

state: () => {  return {    count: 0  }} 

必须是一个返回状态对象的函数。

getters

定义 getter 计算属性:

getters: {  double(state) {    return state.count * 2  }}

getter 能够接管参数:

getters: {  getMessage(state) {    return (name = 'Vue') => `Hello ${name}`   }}

actions

定义方法批改状态:

actions: {  increment(amount = 1) {    this.count += amount  }}

actions 反对同步和异步操作。

persist

配置数据长久化,须要应用插件:

persist: {  enabled: true,  strategies: [    {      key: 'my_store',      storage: localStorage,    },  ]} 

应用 Store

通过 useXxxStore() 获取 Store 实例:

import { useMainStore } from '@/stores/main'export default {  setup() {    const main = useMainStore()    main.increment()  } }

读取状态、调用 actions 同 Vue 组件。

读取状态

// 间接读取const count = main.count// 通过计算属性const double = computed(() => main.doubleCount)// 通过 storeToRefsconst { count } = storeToRefs(main)

调用 Actions

main.increment()const message = main.getMessage('Vue')

多个 Store

能够拆分多个 Store 治理不同模块状态:

stores|- user.js|- product.js

独自导出每个 Store 并在组件中应用:

import { useUserStore } from '@/stores/user'import { useProductStore } from '@/stores/product' export default {  setup() {    // ...  }}

Store 能够相互援用:

// userStore.jsimport { useProductStore } from './product'export const useUserStore = defineStore({  // 能够间接应用 productStore})

Setup Store

集体比拟偏向这种语法

也存在另一种定义 store 的可用语法。与 Vue 组合式 API 的 setup 函数 类似,咱们能够传入一个函数,该函数定义了一些响应式属性和办法,并且返回一个带有咱们想裸露进来的属性和办法的对象。

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

在 Setup Store 中:

  • ref() 就是 state 属性
  • computed() 就是 getters
  • function() 就是 actions

Setup store 比 Option Store 带来了更多的灵活性,因为你能够在一个 store 内创立侦听器,并自在地应用任何组合式函数。不过,请记住,应用组合式函数会让 SSR 变得更加简单。

数据长久化

Pinia 默认状态不长久化,能够通过插件实现长久化:

npm install pinia-plugin-persistedstate
import persistedState from 'pinia-plugin-persistedstate'const pinia = createPinia()pinia.use(persistedState) 

在 Store 中配置 persist:

export const useUserStore = defineStore({  persist: {    enabled: true  } }) 

配置 storage 指定存储地位:

persist: {  storage: sessionStorage}

Pinia 插件

Pinia 生态已有许多插件,能够扩大更多功能:

  • pinia-plugin-persistedstate:数据长久化
  • pinia-plugin-debounce:防抖批改状态
  • pinia-plugin-pinia-observable:转换成 Observable

应用插件:

import piniaPluginPersist from 'pinia-plugin-persist'pinia.use(piniaPluginPersist)

Devtools

Pinia反对Vue devtools

购物车示例

咱们来通过一个购物车的例子看看 Pinia 的用法:

// store.jsimport { defineStore } from 'pinia'export const useCartStore = defineStore('cart', {  state: () => {    return {      items: []      }  },  getters: {    total(state) {      return state.items.reduce((total, item) => {         return total + item.price        }, 0)    }  },  actions: {    addItem(item) {      this.items.push(item)    },    removeItem(id) {      this.items = this.items.filter(i => i.id !== id)    }  }})

在组件中应用:

// Cart.vueimport { useCartStore } from '@/stores/cart'setup() {  const cart = useCartStore()  return {    items: cart.items,    total: cart.total  }}

能够看出代码十分简洁直观。

Pinia 插件

Pinia 插件是一个函数,能够选择性地返回要增加到 store 的属性。它接管一个可选参数,即 context

export function myPiniaPlugin(context) {  context.pinia // 用 `createPinia()` 创立的 pinia。   context.app // 用 `createApp()` 创立的以后利用(仅 Vue 3)。  context.store // 该插件想扩大的 store  context.options // 定义传给 `defineStore()` 的 store 的可选对象。  // ...}

而后用 pinia.use() 将这个函数传给 pinia

pinia.use(myPiniaPlugin)

插件只会利用于在 pinia 传递给利用后创立的 store,否则它们不会失效。

实现一个长久化插件

  • getStorage 函数:依据提供的 key 从本地存储中读取数据。如果数据无奈解析或不存在,则返回 null
  • setStorage 函数:将提供的值转换为 JSON 格局,并以指定的 key 保留到本地存储中。
  • DEFAULT_KEY 常量:示意默认的本地存储键名前缀。如果在选项中未提供自定义键名,将应用该默认键名。
  • Options 类型:定义了插件选项对象的类型,蕴含 key(本地存储键名前缀)和 needKeepIds(须要进行长久化的 Pinia 存储的 ID 数组)两个可选属性。
  • piniaPlugin` 函数:这是次要的插件函数,它接管一个选项对象,并返回一个用于解决 Pinia 存储的函数。
import { PiniaPluginContext } from "pinia";import { toRaw } from "vue";// Get data from local storage by keyexport function getStorage(key) {  const data = localStorage.getItem(key);  try {    return JSON.parse(data);  } catch (error) {    return null;  }}// Set data to local storage with a keyexport function setStorage(key, value) {  const data = JSON.stringify(value);  localStorage.setItem(key, data);}const DEFAULT_KEY = "pinia";type Options = {  key?: string;  needKeepIds?: string[];};const piniaPlugin = ({ key = DEFAULT_KEY, needKeepIds = [] }: Options) => {  return (context: PiniaPluginContext) => {    const { store } = context;    const data = getStorage(`${key}-${store.$id}`);    const subscribeToStore = () => {      if (needKeepIds.length === 0 || needKeepIds.includes(store.$id)) {        setStorage(`${key}-${store.$id}`, toRaw(store.$state));      }    };    store.$subscribe(subscribeToStore);    return {      ...data,    };  };};export default piniaPlugin;

图解算法小册

最近整顿了一本算法小册,感兴趣的同学能够加我微信linwu-hi进行获取