vue3 pinia

一個替代vuex的輕量級好用方案,真香。

引入

#main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'

import App from './App.vue'
import router from './router'

const app = createApp(App)

app.use(createPinia())
app.use(router)

app.mount('#app')

pinia的store

#counter.js
import { defineStore } from 'pinia'

function getNewDiscountRate(rate) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(rate * Math.random())
    }, 1000)
  })
}

export const useCounterStore = defineStore({
  id: 'counter',
  state: () => ({
    counter: 0,
    name: 'jason',
    discountRate:10
  }),
  getters: {
    // 方法一
    doubleCount: (state) => { state.counter * 2 },
    // 方法二想用this(可以獲取整個實例)不能用箭頭函式
    doubleCountByRowFunc: function () { return this.counter * 2 }
  },
  actions: {
    // func
    increment() {
      this.counter++
    },
    // asyn func
    async changeDiscountRate() {
      try {
        return this.discountRate = await getNewDiscountRate(this.discountRate)
      } catch (e) {
        throw Error(e)
      }
    }
  }
})

使用

<template>
  <div class="about">
    <h1>This is an about page</h1>
    {{ counter }}
    <br />
    {{ doubleCount }}
    <br />
    {{ name }}
    <button @click="counter++">直接改</button>
    <button @click="clickPatch">用$patch改</button>
    <button @click="clickState">用$state改</button>
  </div>
</template>

<script setup>
import { useCounterStore } from '../stores/counter.js'
import { storeToRefs } from 'pinia'
const store = useCounterStore()
// 使用
let { counter, doubleCount, name } = storeToRefs(store)
function clickPatch() {
  // 更改寫法一
  // store.$patch({
  //   counter: counter.value + 1
  // })
  // 更改寫法二
  store.$patch((state) => {
    state.counter += 1
  })
}

//更改寫法三
function clickState() {
  store.$state = { name: '123' }
}
// 監聽
// 參數一是監聽時候執行的func 參數二是組件銷毀後是否繼續保持監聽預設會自動解除監聽
store.$subscribe((mutation,state)=>{
  console.log(mutation,state)
},true)

// 監聽action回傳promise時候進入after但是要記得再pinia return出來才接的到形參  回傳throw時候進入或是promise reject的時候
store.$onAction(
	({
    name,
    store,
    args,
    after,
    onError,
  }) => {
    const startTime = Date.now()
    console.log(`Start "${name}" with params [${args.join(', ')}].`)
    after((result) => {
      console.log(
        `Finished "${name}" after ${
          Date.now() - startTime
        }ms.\nResult: ${result}.`
      )
    })
    onError((error) => {
      console.warn(
        `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
      )
    })
	}
)
setTimeout(()=>{
store.changeDiscountRate()
},1000)
</script>

<style>
@media (min-width: 1024px) {
  .about {
    min-height: 100vh;
    display: flex;
    align-items: center;
  }
}
</style>

簡單總結

若想要解構出所有store屬性並且保持綁定要使用storeToRefs

改store值方法有

store.$patch(obj)

store.$patch((state)=>(state.xxx=xxx))

store.xxx = xxx

store.$store({})

監聽值

store.$subscribe((mu,state)=>{},boolean)

監聽action

store.$onAction((ctx)=>{},boolean)

重新初始化store

store.$reset()

參考

https://juejin.cn/post/7037238816712687629#heading-0