[Vuex 状態管理] Vuex の基本的な使用法、コア概念の基本的な使用法 状態、ゲッター、ミューテーション、アクション、モジュール

1_アプリケーション状態管理

1.1_状態管理

開発中、アプリケーションはさまざまなデータを処理する必要があり、それらのデータはアプリケーション内の特定の場所に保存される必要があり、これらのデータの管理は状態管理と呼ばれます。

前線で自分の状態をどう管理するか?

  • Vue 開発では、コンポーネント化された開発方法を使用します。
  • そして、コンポーネント内でデータを定義するか、セットアップで使用されるデータを返します。これらのデータは状態と呼ばれます。
  • これらのデータはモジュール テンプレートで使用でき、モジュールは最終的に View と呼ばれる DOM にレンダリングされます。
  • モジュール内でいくつかの動作イベントが生成されます。これらの動作イベントを処理するときに、状態が変更される場合があります。これらの動作イベントはアクションと呼ばれます。

1.2_ 複雑な状態管理

JavaScript で開発されたアプリケーションはますます複雑になっています。

  • JavaScript は、ますます多くの状態と複雑さを管理する必要があります。
  • これらの状態には、サーバーから返されたデータ、キャッシュされたデータ、ユーザー操作によって生成されたデータなどが含まれます。
  • また、特定の要素が選択されているかどうか、読み込みアニメーションを表示するかどうか、現在のページなど、一部の UI ステータスも含まれます。

一方向データ フローの単純さは、アプリケーションで複数のコンポーネントが状態を共有している場合に簡単に崩れてしまいます。

  • 複数のビューは同じ状態に依存します。
  • 異なるビューからのアクションは同じ状態を変更する必要があります。

コンポーネントデータを渡すことで実現できますか?

  • 一部の単純な状態では、props または Provide の転送を通じて状態を共有することが実際に可能です。
  • しかし、複雑な状態管理の場合、単に受け渡して共有するだけでは問題を解決するだけでは明らかに十分ではありません。たとえば、兄弟コンポーネントはどのようにデータを共有するのでしょうか?

1.3_Vuex 状態管理

変化する状態自体を管理することは非常に困難です。

  • 状態間には依存関係があり、状態の変化は別の状態の変化を引き起こし、[表示] ページによっても状態が変化する可能性があります。
  • アプリケーションが複雑な場合、いつ、どのような理由で、どのように状態が変化するか、制御および追跡することが非常に困難になります。

そこで、コンポーネントの内部状態を抽出してグローバルシングルトンとして管理することは考えられないでしょうか?

  • このモードでは、コンポーネント ツリーが巨大な「ビュー」を構成します。
  • ツリー内のどこにいても、どのコンポーネントでも状態を取得したり、動作をトリガーしたりできます。
  • 状態管理のさまざまな概念を定義および分離し、強制的なルールを通じてビューと状態間の独立性を維持することにより、コード側がより構造化され、保守および追跡が容易になります。

これは、Flux、Redux、および Elm から借用した Vuex の背後にある基本的なアイデアです (純粋な関数型言語、redux には参照用のアイデアがあります); Vue 関係者は、状態管理、フォローアップ学習に Pinia を使用することも推奨しています


公式サイトの写真参照
ここに画像の説明を挿入


2_Vuex の基本的な使い方

2.1_インストール

npmインストール


2.2_ストアの作成

すべての Vuex アプリケーションの中核はストア (ウェアハウス) です。ストアは基本的に、アプリケーション内のほとんどの状態を含むコンテナです。

Vuex と単純なグローバル オブジェクトの違いは何ですか?

  • 1 つ目: Vuex の状態ストアは応答性があります。Vue コンポーネントがストアから状態を読み取るときに、ストア内の状態が変化すると、対応するコンポーネントも更新されます。

  • 2 番目: ストア内の状態を直接変更することはできません。

    • ストア内の状態を変更する唯一の方法は、ミューテーションを明示的にコミットすることです。
    • これにより、各状態の変化を追跡しやすくなり、一部のツールでアプリケーションの状態をより適切に管理できるようになります。

デモ:

(1) src フォルダ配下に新規フォルダストアを作成します このフォルダ配下に通常はindex.jsファイルが作成されますが、実際の開発に応じて作成することもできます。

src/store/index.js

import {
    
     createStore } from 'vuex'

const store = createStore({
    
    
  state: () => ({
    
    
    counter: 100
  })
})  

(2) main.jsに登録

import {
    
     createApp } from 'vue'
import App from './App.vue'
import store from './store'

createApp(App).use(store).mount('#app')

(3) App.vueで呼び出される

<template>
  <div class="app">
    <!-- store中的counter -->
    <h2>App当前计数: {
    
    {
    
     $store.state.counter }}</h2>
  </div>
</template>

2.3_ コンポーネント内のストアを使用する

次のようにコンポーネントでストアを使用します。

  • 2.2 デモなどのテンプレート tempte で使用されます。
  • computed などのオプション API で使用されます。
  • セットアップで使用されます。
<template>
  <div class="app">
      <!-- 在模板tempte中使用store -->
    <h2>Home当前计数: {
   
   { $store.state.counter }}</h2>
    <h2>Computed当前计数: {
   
   { storeCounter }}</h2>
    <h2>Setup当前计数: {
   
   { counter }}</h2>
    <button @click="increment">+1</button>
  </div>
</template>

<script>
  export default {
      
      
      //在options api中使用,比如computed;
    computed: {
      
      
      storeCounter() {
      
      
        return this.$store.state.counter
      }
    }
  }
</script>

<!-- 在setup中使用store -->
<script setup>
  import {
      
       toRefs } from 'vue'
  import {
      
       useStore } from 'vuex'

  const store = useStore()
  const {
      
       counter } = toRefs(store.state)
  
  function increment() {
      
      
    store.commit("increment")
  }
</script>

3_コアコンセプトの状態

3.1_単一状態ツリー

Vuex は単一の状態ツリーを使用します。

  • すべてのアプリケーションレベルの状態を含めるには 1 つのオブジェクトを使用します。
  • SSOT (Single Source of Truth) が使用され、単一のデータ ソースに変換することもできます。

これは、各アプリケーションにストア インスタンスが 1 つだけ含まれること、単一状態ツリーとモジュール化が競合しないこと、モジュールの概念が後で関与することも意味します。

単一状態ツリーの利点:

  • 状態情報が複数の Store オブジェクトに保存されている場合、その後の管理とメンテナンスが特に困難になります。
  • したがって、Vuex は単一の状態ツリーを使用して、アプリケーション レベルですべての状態を管理します。
  • 単一の状態ツリーを使用すると、状態のフラグメントを見つける最も直接的な方法が可能になります。
  • また、その後のメンテナンスやデバッグのプロセスでも、管理と保守が非常に便利になります。

3.2_コンポーネントの状態取得

前のデモでは、コンポーネントの状態を取得する方法がわかりました。

もちろん、この方法が少し面倒だと感じる場合 (式が長すぎる場合)、計算されたプロパティを使用することもできます。

    computed: {
    
    
      storeCounter() {
    
    
        return this.$store.state.counter
      }
    }

ただし、取得する必要がある状態が多数ある場合は、次のmapStateヘルパー関数を使用できます。

  • MapState のメソッド 1: オブジェクト タイプ。
  • MapState の 2 番目のメソッド: 配列型。
  • スプレッド演算子を使用して、元の計算結果と混合することもできます。

3.3_セットアップでのmapStateの使用

セットアップで単一の状態を取得するのは非常に簡単で、useStore を通じてストアを取得した後に特定の状態を取得するだけです。

しかし、mapStateを使用する場合、どうやって状態を取得するのでしょうか?

(1) デフォルトでは、Vuex は、mapState を使用するあまり便利な方法を提供していません。次の方法は推奨されません。

<template>
  <div class="app">
    <!-- 在模板中直接使用多个状态 -->
    <h2>name: {
   
   { $store.state.name }}</h2>
    <h2>level: {
   
   { $store.state.level }}</h2>
    <h2>avatar: {
   
   { $store.state.avatarURL }}</h2>
  </div>
</template>

<script setup>
  import {
      
       computed } from 'vue'
  import {
      
       mapState, useStore } from 'vuex'

  // 一步步完成,步骤繁琐
  const {
      
       name, level } = mapState(["name", "level"])
  const store = useStore()
  const cName = computed(name.bind({
      
       $store: store }))
  const cLevel = computed(level.bind({
      
       $store: store }))
</script>

(2) 手順を簡素化するために、ここで関数パッケージが実行されます。

src/フック/useState.js

import {
    
     computed } from 'vue'
import {
    
     useStore, mapState } from 'vuex'

export default function useState(mapper) {
    
    
  const store = useStore()
  const stateFnsObj = mapState(mapper)
  
  const newState = {
    
    }
  Object.keys(stateFnsObj).forEach(key => {
    
    
    newState[key] = computed(stateFnsObj[key].bind({
    
     $store: store }))
  })

  return newState
}

関数を使用する

<template>
  <div class="app">
    <!-- 在模板中直接使用多个状态 -->
    <h2>name: {
    
    {
    
     $store.state.name }}</h2>
    <h2>level: {
    
    {
    
     $store.state.level }}</h2>
    <h2>avatar: {
    
    {
    
     $store.state.avatarURL }}</h2>
  </div>
</template>

<script setup>
  import useState from "../hooks/useState"
  // 使用useState封装函数
  const {
    
     name, level } = useState(["name", "level"])
</script>

(3) 以下の方法を使用することをより推奨します。

<template>
  <div class="app">
    <!-- 在模板中直接使用多个状态 -->
    <h2>name: {
   
   { $store.state.name }}</h2>
    <h2>level: {
   
   { $store.state.level }}</h2>
    <h2>avatar: {
   
   { $store.state.avatarURL }}</h2>
  </div>
</template>

<script setup>
  import {
      
       computed, toRefs } from 'vue'
  import {
      
       mapState, useStore } from 'vuex'

  // 3.直接对store.state进行解构(推荐)
  const store = useStore()
  const {
      
       name, level } = toRefs(store.state)
</script>

4_コアコンセプトゲッターズ

4.1 _getter の基本的な使用法

一部のプロパティは変更後に使用する必要がある場合があり、現時点ではゲッターを使用できます。

ここに画像の説明を挿入


4.2_getter の 2 番目のパラメータ

ゲッターは 2 番目のパラメータを受け入れることができます

  getters: {
    
    
    // 2.在该getters属性中, 获取其他的getters
    message(state, getters) {
    
    
      return `name:${
      
      state.name} level:${
      
      state.level} friendTotalAge:${
      
      getters.totalAge}`
    }

  }

4.3 _getterの戻り関数

  getters: {
    
    
    // 3.getters是可以返回一个函数的, 调用这个函数可以传入参数(了解)
    getFriendById(state) {
    
    
      return function(id) {
    
    
        const friend = state.friends.find(item => item.id === id)
        return friend
      }
    }
  }

4.4 _mapGettersの補助関数

MapGetter を使用できるヘルパー関数

<template>
  <div class="app">
    <h2>doubleCounter: {
   
   { doubleCounter }}</h2>
    <h2>friendsTotalAge: {
   
   { totalAge }}</h2>
    <!-- 根据id获取某一个朋友的信息 -->
    <h2>id-111的朋友信息: {
   
   { getFriendById(111) }}</h2>
    <h2>id-112的朋友信息: {
   
   { getFriendById(112) }}</h2>
  </div>
</template>

<script>
  import {
      
       mapGetters } from 'vuex'

  export default {
      
      
    computed: {
      
      
      ...mapGetters(["doubleCounter", "totalAge"]),
      ...mapGetters(["getFriendById"])
    }
  }
</script>

セットアップでも使えます

<template>
  <div class="app">
    <h2>message: {
   
   { message }}</h2>
  </div>
</template>

<script setup>
  import {
      
       computed, toRefs } from 'vue';
  import {
      
       mapGetters, useStore } from 'vuex'

  const store = useStore()

  // 1.使用mapGetters ,较麻烦
  // const { message: messageFn } = mapGetters(["message"])
  // const message = computed(messageFn.bind({ $store: store }))

  // 2.直接解构, 并且包裹成ref
  // const { message } = toRefs(store.getters)

  // 3.针对某一个getters属性使用computed
  const message = computed(() => store.getters.message)
</script>

5_コアコンセプト 突然変異

Vuex ストアの状態を変更する唯一の方法は、ミューテーションを送信することです

5.1_使用

ミューテーションを送信すると、一部のデータが送信されます。このとき、パラメーターを使用できます。ペイロードはオブジェクト タイプであることに注意してください。

mutation :{
    
    
 add(state,payload){
    
    
   statte.counter + = payload
 }
}

提出する

$store.commit({
    
    
  type: "add",
  count: 100
})

5.2_ミューテーション定数型

デモ:

(1) mutation-type.jsに定数を定義する

export const CHANGE_INFO = "changeInfo"

(2) ストア内の定数を使用する

  mutations: {
    
    
      [CHANGE_INFO](state, newInfo) {
    
    
      state.level = newInfo.level
      state.name = newInfo.name
    }
  }

(3) 使用中
ここに画像の説明を挿入


5.3 突然変異の重要な原則

重要な原則は、突然変異は同期関数でなければならないということです。

  • これは、devtool ツールが変更ログを記録するためです。
  • すべての突然変異は記録され、devtools は前の状態と次の状態のスナップショットをキャプチャする必要があります。
  • ただし、非同期操作がミューテーションで実行される場合、データの変更を追跡できません。

6_コアコンセプト アクション

6.1_基本的な使い方

アクションは突然変異に似ていますが、違いは次のとおりです。

  • アクションは状態を直接変更するのではなく、突然変異を送信します。

  • アクションには任意の非同期操作を含めることができます。

非常に重要なパラメーター コンテキストがあります。

  • context は、ストア インスタンスと同じメソッドとプロパティを持つコンテキスト オブジェクトです。
  • したがって、そこから commit メソッドを取得してミューテーションを送信したり、context.state と context.getters を通じて状態とゲッターを取得したりできます。

特定のケースについては、この記事を参照してください: https://blog.csdn.net/qq_21980517/article/details/103398686


6.2_配信操作

ここに画像の説明を挿入


6.3_actions の非同期操作

通常、アクションは非同期であり、アクションに Promise を返させることでアクションがいつ終了するかを知ることができ、その後、Promise の中で完了した操作を処理できます。

デモ:

Index.js で、ネットワーク リクエストの送信を例に挙げます。

action{
    
    
	fetchHomeMultidataAction(context) {
    
    
      // 1.返回Promise, 给Promise设置then
      // fetch("http://123.207.32.32:8000/home/multidata").then(res => {
    
    
      //   res.json().then(data => {
    
    
      //     console.log(data)
      //   })
      // })
      
      // 2.Promise链式调用
      // fetch("http://123.207.32.32:8000/home/multidata").then(res => {
    
    
      //   return res.json()
      // }).then(data => {
    
    
      //   console.log(data)
      // })
      return new Promise(async (resolve, reject) => {
    
    
        // 3.await/async
        const res = await fetch("http://123.207.32.32:8000/home/multidata")
        const data = await res.json()
        
        // 修改state数据
        context.commit("changeBanners", data.data.banner.list)
        context.commit("changeRecommends", data.data.recommend.list)

        resolve("aaaaa")
      })
    }
 }   

test3.vue中

<script setup>
  import {
    
     useStore } from 'vuex'
  // 告诉Vuex发起网络请求
  const store = useStore()
  store.dispatch("fetchHomeMultidataAction").then(res => {
    
    
    console.log("home中的then被回调:", res)
  })

</script>



7_ コアコンセプトモジュール

7.1_module の基本的な使用法

モジュールの理解は?

  • 単一の状態ツリーを使用するため、アプリケーションのすべての状態は比較的大きなオブジェクトに集中し、アプリケーションが非常に複雑になると、ストア オブジェクトが非常に肥大化する可能性があります。
  • 上記の問題を解決するために、Vuex ではストアをモジュール (モジュール) に分割することができます。
  • 各モジュールには独自の状態、突然変異、アクション、ゲッター、さらにはネストされたサブモジュールがあります。
    ここに画像の説明を挿入

7.2_module のローカル状態

モジュール内のミューテーションとゲッターの場合、最初に受け取られるパラメータはモジュールのローカル状態オブジェクトです。
ここに画像の説明を挿入


7.3_module の名前空間

デフォルトでは、モジュール内のアクションとミューテーションは引き続きグローバル名前空間に登録されます。

  • これにより、複数のモジュールが同じアクションまたは突然変異に応答できるようになります。
  • ゲッターはデフォルトでグローバル名前空間にも登録されます。

モジュールに高度なカプセル化と再利用性を持たせたい場合は、namespaced: true を追加して、名前空間を持つモジュールにすることができます。モジュールが登録されると、そのすべてのゲッター、アクション、およびミューテーションは、登録されたパスに従って自動的に調整されます。モジュール名で

デモ:カウンター、js

const counter = {
    
    
  namespaced: true, //命令空间
  state: () => ({
    
    
    count: 99
  }),
  mutations: {
    
    
    incrementCount(state) {
    
    
      console.log(state)
      state.count++
    }
  },
  getters: {
    
    
    doubleCount(state, getters, rootState) {
    
    
      return state.count + rootState.rootCounter
    }
  },
  actions: {
    
    
    incrementCountAction(context) {
    
    
      context.commit("incrementCount")
    }
  }
}

export default counter

7.4_module ルートコンポーネントを変更または配布する

アクションのルートで状態を変更するには、次の方法があります。
ここに画像の説明を挿入

Supongo que te gusta

Origin blog.csdn.net/qq_54075517/article/details/132574963
Recomendado
Clasificación