Skip to content

Pinia

安裝

照官方網站安裝,或是採用 vite 時就裝好了。

建立 store

在/stores 建立檔案

  • 內容參考 Defining a Store
    • 以下範例是用 Options API,另外 Setup Stores 有教使用 Vue Composition API 的設定方式
js
//Pinia 與 Options API 章節
import { defineStore } from "pinia";

//自定命名
const useUserStore = defineStore("user store", {
  // other options...

  //類似 Data
  state: () => ({ wallet: 300, name: "Eduardo" }),
  ///類似 Computed
  getters: {
    getUserName: (state) => `你好,${state.name}`,
  },
  ///類似 Methods
  actions: {
    updateName() {
      this.name = "小美";
    },
  },
});

export default useUserStore;

Getters [Option API 寫法]

Getters are exactly the equivalent of computed values for the state of a Store.

  • Getters
  • 可以用於根據資料做排序等作法。
js
export const useCounterStore = defineStore("counter", {
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
});
//取 doubleCount 跟取 count 一樣寫法

使用

  • core-concepts/#Using-the-store 使用上有跟 option API 跟 composition 的用法,後者修改用法比較多,先以後者為範例。
    • 抓取到資料後,可以直接改值,store 資料會改變。
    • 可以用解構+storeToRefs 後用 value 改值。
    • 方法可以直接解構出來
    • 也可以自訂方法 用 user.$patch 與 user.$reset 設定資料。
<template>
  <div>
    <div>不解構的用法 </div>
    <code>const user = useUserStore();</code>
    {{ user.name }}
    <div> {{ user.getUserName }}</div>
    <button type="button" @click="user.updateName">按我觸發 updateName</button>


    <div>解構的用法</div>
    {{ name }} {{ wallet }}
    <button type="button" @click="updateName">按我觸發 updateName</button>

    <button type="button" @click="updateData">按我觸發 updateData</button>
    <button type="button" @click="reset">按我觸發 reset</button>
  </div>
</template>


<script>
import useUserStore from '@/stores/user'
import {storeToRefs} from 'pinia'
export default {
  setup() {
    const user = useUserStore();
    user.name = "被我改名了"

    const {name, wallet} = storeToRefs(user);
    name.value = "換個解構取值"

    const {updateName} = user;

    function updateData() {
      user.$patch(
        {
          name: "資料 patch 更名了"
        }
      )
    }
    function reset(params) {
      user.$reset();

    }

    return {user, name, wallet, updateName, updateData, reset}
  }

}
</script>

使用 改寫 [vue2 to vue3]

js
import {mapState, mapActions} from 'pinia'/

import { storeToRefs } from 'pinia'; /
const orderStore =useOrderStore()
const { order,status } = storeToRefs(orderStore);
const { getOrderByID,payOrderByID } = orderStore;


  computed: {/
    ...mapState(useOrderStore, ['order', 'status']),/

  },

  methods: {/
    ...mapActions(useOrderStore, ['getOrderByID', 'payOrderByID']),/

監聽 state

監聽所有

js
import { useOrderStore } from "@/stores/orderStore";
const orderStore = useOrderStore();
watch(
  useOrderStore,
  (state) => {
    console.log(`watch here`, state);
  },
  { deep: true }
);

監聽單一

js
watch(
  () => orderStore.isOrderSendSuccess,
  (newVlue) => {
    console.log("newVlue.title.watch>>>", newVlue);
  }
);

//需注意 如果監聽的是物件 要加上 deep
watch(
  () => orderStore.status.orderTemp,
  (newVal) => {
    if (newVal.paySuccess) {
      emit("order-create", newVal.orderId);
      emit("go-next");
    }
    getCart();
  },
  { deep: true }
);
  • 錯誤寫法
js
const { order, status, isOrderSendSuccess } = storeToRefs(useOrderStore);

watch(
  () => isOrderSendSuccess,
  (newVlue) => {
    console.log("newVlue.title.watch>>>", newVlue);
  }
);

在你的 watch 中,isOrderSendSuccess 是一个 ref 对象的解构,而不是一个函数或响应式状态,因此 watch 监听不到它的变化。你应该监听 orderStore.isOrderSendSuccess 而不是解构后的变量

options 寫法

js

 computed: {
    ...mapState(useProductStore, ['products', 'status'])
  },
  watch: {
    products: {
      handler: function (val, oldVal) {
      //做一些事
        }
      }
    },
  },

composition 寫法

js
// 錯誤寫法 裡面要用箭頭 A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types.
// watch(pagination.value.current_page, (newValue, oldValue) => {
//   window.scrollTo({top: 0, behavior: 'smooth'});
// });
const pagination = ref({ 等等 });
watch(
  () => pagination.value.current_page,
  (newValue, oldValue) => {
    window.scrollTo({ top: 0, behavior: "smooth" });
  }
);

computed 寫法

  • counter.ts
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'

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

  return { count, doubleCount, increment }
})

TODO

  • [ ]pinia 響應變化?
  • [ ]pinia data race?