乐趣区

关于前端:一杯茶的时间入门Vue新的状态管理库Pinia

点击在线浏览,体验更好 链接
古代 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)

// 通过 storeToRefs
const {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.js
import {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.js
import {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.vue

import {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 key
export function getStorage(key) {const data = localStorage.getItem(key);
  try {return JSON.parse(data);
  } catch (error) {return null;}
}

// Set data to local storage with a key
export 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 进行获取

退出移动版