Vue3——第十四章 (Pinia: Vue Store Worth Your Love)

1.ピニアの紹介

  • Pinia は、コンポーネントまたはページ間で状態を共有できる Vue 固有の状態管理ライブラリです。
  • Pinia は、Vuex の次のイテレーションを調査するための実験として開始されたため、Vuex 5 コア チームの議論から多くのアイデアが組み込まれています。
  • mutation廃止されました。多くの場合、それらは非常に冗長であると見なされます。彼らの当初の意図は、devtools 統合ソリューションを提供することでしたが、これはもはや問題ではありません。
  • Vuex 3.x 只适配 Vue 2,而 Vuex 4.x 是适配 Vue 3 的。
  • 非常に軽量: Pinia のサイズはわずか約 1kb です。
  • 開発ツールのサポート: Vue 2 であろうと Vue 3 であろうと、Vue devtools フックをサポートする Pinia は、より優れた開発エクスペリエンスを提供します。
  • Type-safe : 型は自動的に推測され、JavaScript でもオートコンプリートが提供されます!
  • Pinia は、2019 年 11 月頃に構成 API を使用して Vue 状態管理ライブラリを設計する実験として開始されました。
  • それ以来、Vue 2 と Vue 3 の両方をサポートする傾向があり、開発者はコンポジション API の使用を強制されていません。

2. 基本例

  • pinia API の基本的な使い方は以下のとおりです。
  • 最初にストアを作成できます。
// stores/counter.js
import {
    
     defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
    
    
  state: () => {
    
    
    return {
    
     count: 0 }
  },
  // 也可以这样定义
  // state: () => ({ count: 0 })
  actions: {
    
    
    increment() {
    
    
      this.count++
    },
  },
})
  • より高度な使い方として、関数 (コンポーネントの setup() と同様) を使用して Store を定義することもできます。
export const useCounterStore = defineStore('counter', () => {
    
    
  const count = ref(0)
  function increment() {
    
    
    count.value++
  }

  return {
    
     count, increment }
})
  • 次に、コンポーネントでストアを使用できます。
import {
    
     useCounterStore } from '@/stores/counter'

export default {
    
    
  setup() {
    
    
    const counter = useCounterStore()

    counter.count++
    // 带有自动补全 ✨
    counter.$patch({
    
     count: counter.count + 1 })
    // 或者使用 action 代替
    counter.increment()
  },
}
  • setup() 関数と合成 API に慣れていない場合、Pinia は、mapStores()、mapState()、または mapActions() を通じてアクセスされる、Vuex のマッピング状態に似た一連の補助関数も提供します。
export default {
    
    
  computed: {
    
    
    // 其他计算属性
    // ...
    // 允许访问 this.counterStore 和 this.userStore
    ...mapStores(useCounterStore, useUserStore)
    // 允许读取 this.count 和 this.double
    ...mapState(useCounterStore, ['count', 'double']),
  },
  methods: {
    
    
    // 允许读取 this.increment()
    ...mapActions(useCounterStore, ['increment']),
  },
}
  • 非コンポーネント js ファイルでの使用:

import {
    
     useCounterStore } from '@/stores/counter'

function xxxx = () =>{
    
    
   const counter = useCounterStore()
   counter.count++
   counter.increment()
}

3. コアコンセプト

1.ストアを定義する

  • Store は defineStore() で定義されており、その最初のパラメーターには一意の名前が必要であることを知っておく必要があります。
import {
    
     defineStore } from 'pinia'

// 你可以对 `defineStore()` 的返回值进行任意命名
// 但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。(比如 `useUserStore`,`useCartStore`,`useProductStore`)
// 第一个参数是你的应用中 Store 的唯一 ID。
export const useStore = defineStore('main', {
    
    
  // 其他配置...
})
  • ID としても使用されるこのname は必須であり、Pinia はそれを使用してストアを devtools に接続します。
  • defineStore()の 2 番目のパラメーターは、Setup 関数または Option オブジェクトの 2 種類の値を受け入れます。
  • Vue のオプション API と同様に、状態、アクション、およびゲッター プロパティを持つ Option オブジェクトを渡すこともできます。
// 可以认为 state 是 store 的数据 (data)
//getters 是 store 的计算属性 (computed)
//而 actions 则是方法 (methods)
export const useCounterStore = defineStore('counter', {
    
    
  state: () => ({
    
     count: 0 }),
  getters: {
    
    
    double: (state) => state.count * 2,
  },
  actions: {
    
    
    increment() {
    
    
      this.count++
    },
  },
})
  • Vue コンポジション API の setup 関数と同様に、リアクティブなプロパティとメソッドを定義する関数を渡し、公開したいプロパティとメソッドを含むオブジェクトを返すことができます。
export const useCounterStore = defineStore('counter', () => {
    
    
  const count = ref(0)
  function increment() {
    
    
    count.value++
  }

  return {
    
     count, increment }
})
  • セットアップ ストア:ref() 就是 state 属性、computed() 就是 getters、function() 就是 actions
  • セットアップ ストアは、ストア内にリスナーを作成し、任意の構成機能を自由に使用できるため、オプション ストアよりも柔軟性があります。

2、状態

  • ほとんどの場合、状態はストアの中心です。
  • 通常、アプリを表す状態を定義することから始めます。
  • Pinia では、state は初期状態を返す関数として定義されています。これにより、Pinia はサーバーとクライアントの両方をサポートできます。
import {
    
     defineStore } from 'pinia'

const useStore = defineStore('storeId', {
    
    
  // 为了完整类型推理,推荐使用箭头函数
  state: () => {
    
    
    return {
    
    
      // 所有这些属性都将自动推断出它们的类型
      count: 0,
      name: 'Eduardo',
      isAdmin: true,
      items: [],
      hasChanged: true,
    }
  },
})
  • 默认情况下,你可以通过 store 实例访问 state,直接对其进行读写。
const store = useStore()

store.count++
  • 可以通过调用 store 的 $reset() 方法将 state 重置为初始值。
const store = useStore()

store.$reset()
  • 除了用 store.count++ 直接改变 store,你还可以调用 $patch 方法。它允许你用一个 state 的补丁对象在同一时间更改多个属性:
store.$patch({
    
    
  count: store.count + 1,
  age: 120,
  name: 'DIO',
})
  • $patch 方法也接受一个函数来组合这种难以用补丁对象实现的变更。
store.$patch((state) => {
    
    
  state.items.push({
    
     name: 'shoes', quantity: 1 })
  state.hasChanged = true
})
  • 你不能完全替换掉 store 的 state,因为那样会破坏其响应性。但是,你可以 patch 它。
// 这实际上并没有替换`$state`
store.$state = {
    
     count: 24 }
// 在它内部调用 `$patch()`:
store.$patch({
    
     count: 24 })

3、ゲッター

  • getter は、ストアの状態の計算値とまったく同じです。
  • これらは、defineStore() の getters プロパティを介して定義できます。アロー関数が推奨され、最初の引数として状態を受け取ります。
export const useStore = defineStore('main', {
    
    
  state: () => ({
    
    
    count: 0,
  }),
  getters: {
    
    
    doubleCount: (state) => state.count * 2,
  },
})
  • ほとんどの場合、ゲッターは状態のみに依存しますが、他のゲッターも使用する場合があります。
  • したがって、通常の関数でゲッターを定義する場合でも、これを介してストア インスタンス全体にアクセスできます。
export const useStore = defineStore('main', {
    
    
  state: () => ({
    
    
    count: 0,
  }),
  getters: {
    
    
    // 自动推断出返回类型是一个 number
    doubleCount(state) {
    
    
      return state.count * 2
    },
    // 返回类型**必须**明确设置
    doublePlusOne(): number {
    
    
      // 整个 store 的 自动补全和类型标注 ✨
      return this.doubleCount + 1
    },
  },
})
  • 次に、ストア インスタンスのゲッターに直接アクセスできます。
<template>
  <p>Double count is {
    
    {
    
     store.doubleCount }}</p>
</template>

<script>
export default {
    
    
  setup() {
    
    
    const store = useStore()

    return {
    
     store }
  },
}
</script>

4、アクション

  • アクションはコンポーネントのメソッドに相当します。
  • これらは defineStore() の actions 属性を介して定義でき、ビジネス ロジックの定義にも最適です。
export const useStore = defineStore('main', {
    
    
  state: () => ({
    
    
    count: 0,
  }),
  actions: {
    
    
    increment() {
    
    
      this.count++
    },
    randomizeCounter() {
    
    
      this.count = Math.round(100 * Math.random())
    },
  },
})
  • ゲッターと同様に、アクションはこれを介してストア インスタンス全体にアクセスすることもでき、完全な型注釈 (およびオートコンプリート ✨) をサポートします。
  • 違いは、アクションは非同期にすることができ、await を使用して任意の API を呼び出すことができ、他のアクションも実行できることです!
import {
    
     mande } from 'mande'

const api = mande('/api/users')

export const useUsers = defineStore('users', {
    
    
  state: () => ({
    
    
    userData: null,
    // ...
  }),

  actions: {
    
    
    async registerUser(login, password) {
    
    
      try {
    
    
        this.userData = await api.post({
    
     login, password })
        showTooltip(`Welcome back ${
      
      this.userData.name}!`)
      } catch (error) {
    
    
        showTooltip(error)
        // 让表单组件显示错误
        return error
      }
    },
  },
})
  • アクションはメソッドのように呼び出すことができます:
export default defineComponent({
    
    
  setup() {
    
    
    const main = useMainStore()
    // 作为 store 的一个方法调用该 action
    main.randomizeCounter()

    return {
    
    }
  },
})
  • 別のストアを使用する場合は、アクションで直接呼び出すことができます。
import {
    
     useAuthStore } from './auth-store'

export const useSettingsStore = defineStore('settings', {
    
    
  state: () => ({
    
    
    preferences: null,
    // ...
  }),
  actions: {
    
    
    async fetchUserPreferences() {
    
    
      const auth = useAuthStore()
      if (auth.isAuthenticated) {
    
    
        this.preferences = await fetchPreferences()
      } else {
    
    
        throw new Error('User must be authenticated')
      }
    },
  },
})

おすすめ

転載: blog.csdn.net/weixin_44733660/article/details/128675886