次世代のvue状態管理ツールpinia、この素敵なパイナップルを見に来てください

vuex @ 4.xを試した学生は、tsのサポートがあまり良くなく、書くのもあまり便利ではないことを知っています。わからない方はこちらの記事をお読みください

ピニア公式サイト

ピニアの簡単な紹介

Piniaは、Vue.jsチームのメンバーであるPhan Anによって開発された新世代のステートマネージャーであるため、次世代のVuex、つまりVuex5.xとも見なされます。そして、公式アカウントに追加されます

Piniaには次の機能があります。

  • オプションAPIとコンポジションAPIをサポートします。
  • 完全なタイプスクリプトのサポート。
  • ミューテーションを削除し、状態、ゲッター、アクションのみを削除します。
  • アクションは同期と非同期の両方をサポートします。
  • モジュールのネストはなく、フラットモジュール編成方式によりコード作成プロセスが大幅に簡素化されます。
  • 自動コード分割。
  • vuedevtoolsをサポートします。

インストール

    npm install pinia
    // yarn add pinia
复制代码

ライブラリをvueに登録します。

import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'

const app = createApp(App)

app.use(createPinia())
app.mount('#app')
复制代码

核心概念

Piniaは、使用法の観点からはvuexとほぼ同じです。defineStoreでコンテナオブジェクトを作成します

前のvuexの状態です。コンポーネントのデータと同様に、モジュールの下にデータを保存します。

    import { defineStore } from 'pinia'

    const useUserStore = defineStore('user', {
      state: () => {
        return {
          name "zh",
          age: 20,
          friends: []
        }
      }
    })
复制代码

状態のデータを取得して変更するにはどうすればよいですか?以下に紹介しましょう。

状態プロパティを取得します

モジュールを直接インポートする

    <ul>
      <li>姓名: {{ userStore.name }}</li>
      <li>年龄: {{ userStore.age }}</li>
      <li>朋友: {{ userStore.friends }}</li>
    </ul>
    
   import useUserStore from '../store/userStore'

    const userStore = useUserStore()
复制代码

上記の値が非常に面倒であることを見て、それを分解させてください。

    <ul>
      <li>姓名: {{ name }}</li>
      <li>年龄: {{ age }}</li>
      <li>朋友: {{ friends }}</li>
    </ul>

    // 不能直接解构,结构后数据将不再是响应式。
    const { name, age, friends } = userStore
复制代码

上記も表示できるようですが、問題ありませんので、データを変更してインターフェースの変化を見てみましょう。

    <h1>响应式state数据</h1>
    <ul>
      <li>姓名: {{ userStore.name }}</li>
      <li>年龄: {{ userStore.age }}</li>
      <li>朋友: {{ userStore.friends }}</li>
    </ul>

    <h1>非响应式state数据,通过解构</h1>
    <ul>
      <li>姓名: {{ name }}</li>
      <li>年龄: {{ age }}</li>
      <li>朋友: {{ friends }}</li>
    </ul>

    <button @click="handleUserState">修改数据:handleUserState</button>
    const handleUserState = () => {
      userStore.$patch((state) => {
        state.name = 'llm'
        state.age = 30
        state.friends.push('llm', 'zh')
      })
    }
复制代码

btn2.gif上記のgifからわかるように、基本データ型は応答しませんが、参照データ型は応答します。この問題、さまざまな方法で状態を変更すると、さまざまな効果があります。状態が返すデータの参照の問題のため。直接変更した後も、返されたオブジェクトは元のオブジェクトのままであり、$patchおよびアクションディスパッチによる戻りは元のオブジェクトへの参照。。)それでも、状態を分解したい場合は、piniaが提供するものを使用してサービスを提供する必要がありますstoreToRefs

     <h1>响应式state数据,通过解构</h1>
    <ul>
      <li>姓名: {{ reactiveName }}</li>
      <li>年龄: {{ reactiveAge }}</li>
      <li>朋友: {{ reactiveFriends }}</li>
    </ul>
    // 将其变为响应式
    const {
      name: reactiveName,
      age: reactiveAge,
      friends: reactiveFriends,
    } = storeToRefs(userStore)
复制代码

react.gif

状態プロパティを変更します

  • 直接変更する
  userStore.name = 'llm'
复制代码
  • $patch一括編集する
    • オブジェクトを直接渡すことができます。モジュールをインポートして、変更する状態値を取得します。
    • 関数を渡すこともできます。この関数は、状態をパラメーターとして受け取ります。
// 这种方式只有基本数据类型不能响应式
 userStore.$patch((state) => {
    state.name = 'llm'
    state.age = 30
    state.friends.push('llm', 'zh')
  })
  
  // 这种方式任何数据都不能作为响应式
    userStore.$patch({
        name: 'llm',
        age: 30,
        friends: [...userStore.friends, 'zh', 'llm'],
    })
复制代码
  • アクションによって派遣されます。
    // useUserStore.js
    import { defineStore } from 'pinia'
    const useUserStore = defineStore('user', {
      state: () => {
        return {
          name: 'zh',
          age: 20,
          friends: []
        }
      },
      actions: {
        changeState() {
          this.name = 'llm'
          this.age = 30
          this.friends.push('zj', 'llm')
        }
      }
    })
复制代码
  // vue
  userStore.changeState()
复制代码

これらの方法については、アクションディスパッチを使用して統合管理を実現することをお勧めします。状態オブジェクトを破棄するときは、必ずstoreToRefsAPIを使用してください。

アクション

前述のように、状態を更新することです。vuexのアクションと同じです。しかし、使用法は変更されました。データを管理する場合は、基本的に管理に適したアクションディスパッチ機能を使用しています。以下をご覧ください。

基本的な使用法

それを介して直接状態のデータを取得しますthis

     // useUserStore.js
    import { defineStore } from 'pinia'
    const useUserStore = defineStore('user', {
      state: () => {
        return {
          name: 'zh',
          age: 20,
          friends: []
        }
      },
      actions: {
        changeState() {
          this.name = 'llm'
          this.age = 30
          this.friends.push('zj', 'llm')
        }
      }
    })
复制代码

コンポーネントでは、このモジュールを介してアクション関数を直接呼び出すことができます。

  userStore.changeState()
复制代码

非同期データの処理

    // 更新异步数据
    getSong() {
      axios({
        url: 'http://123.207.32.32:9001/song/detail?ids=1441758494'
      }).then((res) => {
        console.log('res', res.data.songs[0])
      })
    }
复制代码

他のストアモジュールのアクション関数で使用する

実際、他のモジュールのストアをインポートしてから、対応するアクションを直接呼び出すことです。

    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')
          }
        },
      },
    })
复制代码

ゲッター

使用法はvuexのゲッターと同じです。計算されたプロパティに似ていますが、キャッシュ機能があります。パフォーマンスの最適化に役立ちます。

基本的な使用法

  • 他のゲッターはゲッター関数で使用できます。

これから直接入手できます。

import { defineStore } from 'pinia'

const useUserStore = defineStore('user', {
  // arrow function recommended for full type inference
  state: () => {
    return {
      name: 'zh',
      age: 20,
      friends: [],
      song: {},
      discount: 0.6,
      books: [
        { name: '深入Vuejs', price: 200, count: 3 },
        { name: '深入Webpack', price: 240, count: 5 },
        { name: '深入React', price: 130, count: 1 },
        { name: '深入Node', price: 220, count: 2 }
      ]
    }
  },
  getters: {
    currentDiscount(state) {
      return state.discount * 0.9
    },
    totalPrice(state) {
      let _totalPrice = 0
      for (const book of state.books) {
        _totalPrice += book.count * book.price
      }
      return _totalPrice * this.currentDiscount
    }
  }
})
复制代码
  • getter関数にパラメーターを渡したい場合は、getterに関数を返させ、それを外部で呼び出して、パラメーターを渡すことができます。
  getters: {
    currentDiscount(state) {
      return state.discount * 0.9
    },
    totalPrice(state) {
      let _totalPrice = 0
      for (const book of state.books) {
        _totalPrice += book.count * book.price
      }
      return _totalPrice * this.currentDiscount
    },
    totalPriceCountGreaterN(state) {
      return function (n) {
        let totalPrice = 0
        for (const book of state.books) {
          if (book.count > n) {
            totalPrice += book.count * book.price
          }
        }
        return totalPrice * this.currentDiscount
      }
    }
  }
复制代码
// vue
<h1>getters展示</h1>
<div>{{ userStore.totalPrice }}</div>
<div>{{ userStore.totalPriceCountGreaterN(2) }}</div>
复制代码

image.png

他のストアモジュールのゲッターを使用する

    import { useOtherStore } from './other-store'

    export const useStore = defineStore('main', {
      state: () => ({
        // ...
      }),
      getters: {
        otherGetter(state) {
          const otherStore = useOtherStore()
          return state.localData + otherStore.data
        },
      },
    })
复制代码

予防

getter関数を定義すると、stateパラメーターを受け入れることができます。

  • 受け入れられず、tsが使用されている場合は、戻り値のタイプを指定する必要があります。
  • 受け入れられた場合、戻り値のタイプは指定されない場合があります。

ブラザーズ、ピニアは本当に美味しいです。モジュールを入れ子にしないと、tsのサポートはさらに良くなります。まだ学んでいない場合は、急いでください。vuexを学んだ人にとっては、始めるのは簡単です。

役立つ場合は、星をクリックするだけです。ありがとうございました。

おすすめ

転載: juejin.im/post/7084497267809320990