1. 程式人生 > 其它 >個人自學前端27-Vue4-狀態管理

個人自學前端27-Vue4-狀態管理

目錄

一.狀態管理

假設當一個數據變化時,多個元件同時更新檢視. => 狀態管理 => 應該把資料放到多個元件的共同祖先元件上

什麼叫狀態? => 狀態就是響應式資料和呈現它的檢視.
元件的狀態是由它的資料和檢視決定的.
狀態管理 => 資料和檢視管理.

狀態管理 => 如何實現多個元件共用一個狀態?

  1. 把資料和修改資料的邏輯放在父元件上.子元件通過props獲取父元件資料,再通過自定義事件觸發父元件修改資料的邏輯.(父傳子,子傳父)
  2. Vuex.(Vue的外掛 => Vue的全域性狀態管理)

二.Vuex

Vuex如何實現:

  1. 如何例項化Vuex資料倉庫.(用於存放資料和修改資料的邏輯)
  2. 元件如何獲取Vuex的資料
  3. 元件如何修改Vuex的資料
  4. 如何把Vuex的資料和邏輯對映成元件的資料和邏輯

1. 如何例項化Vuex資料倉庫.(用於存放資料和修改資料的邏輯)

例項化一個數據倉庫.例項化之後,還需要掛載到Vue例項上.
掛載到new Vue上,就是全域性的狀態管理。所有的元件,都可以訪問到state內的資料。
如果掛載到指定的元件A上,則元件A以及元件A的所有子孫元件,都可以訪問到state內的資料。

    // 例項化一個數據倉庫
    const store = new Vuex.Store({
      // 多個元件共用的狀態.(資料)
      state: {
        count: 0
      }
    })
    new Vue({
      el: '#app',
      components: {App},
      template: `<App />`,
      // store: store
      // 掛載store
      store
    });

2. 元件如何獲取Vuex的資料

掛載完成後,就可以通過Vuex的例項store來訪問state內的資料。
vue元件內可以通過this.$store來獲取這個state的例項。

    const box = {
      template: `
        <div>
          <h3>box元件---{{count}}</h3>
          <button>box--count++</button>
        </div>
      `,
      computed: {
        count() {
          // 獲取state的例項
          return this.$store.state.count
        }
      },
    }

3. 元件如何修改Vuex的資料

  1. 修改state資料的邏輯,需要通過mutations選項寫在資料倉庫中,可以寫多個方法.
    mutations內的方法的第一個引數是state物件,第二個引數是元件傳遞的引數.
    元件觸發mutations內的方法,需要同this.$store.commit來觸發.
    commit('mutation的方法名', 元件實參);
    const store = new Vuex.Store({
      // 多個元件共用的狀態.(資料)
      state: {
        count: 10000
      },
      // 修改state內資料的邏輯.
      mutations: {
        // count+1
        plus(state, num) {
          state.count += num;
        },
        // count-1
        reduce(state, num) {
          state.count -= num
        }
      }
    });
    const box = {
      template: `
        <div>
          <h3>box元件---{{count}}</h3>
          <button @click='$store.commit("plus", 1)'>box--count++</button>
          <button @click='$store.commit("reduce", 1)'>box--count--</button>
        </div>
      `,
      computed: {
        count() {
          return this.$store.state.count
        }
      },
    }
  1. 如果有非同步操作的需求,需要通過actions來實現
    actions方法內觸發mutations方法.
    actions的觸發方式是dispatch.
    dispatch('actions的方法名', 元件實參);
    const store = new Vuex.Store({
      // 嚴格模式.禁止在mutations之外修改state.
      // 如果在mutations之外修改state,會報這個錯[vuex] do not mutate vuex store state outside mutation handlers.
      strict: true,
      // 多個元件共用的狀態.(資料)
      state: {
        count: 10000
      },
      // 修改state內資料的邏輯.
      mutations: {
        // count+1
        plus(state, num) {
          state.count += num
        },
        // count-1
        reduce(state, num) {
          state.count -= num
        }
      },
      // 非同步觸發mutations
      actions: {
        asyncPlus(store, num) {
          // 2秒後觸發mutations的plus方法修改state。
          setTimeout(() => {
            store.commit("plus", num);
          }, 2000);
        }
      }
    });

    const box = {
      template: `
        <div>
          <h3>box元件---{{count}}</h3>
          <button @click='$store.dispatch("asyncPlus", 1)'>box--count++</button>
          <button @click='$store.commit("reduce", 1)'>box--count--</button>
        </div>
      `,
      computed: {
        count() {
          return this.$store.state.count
        }
      },
    }

4. 如何把Vuex的資料和邏輯對映成元件的資料和邏輯

map對映:

  1. 把state的資料變成元件資料.
  2. 把mutations和actions的方法變成元件方法.
    const { mapState, mapMutations, mapActions }  = Vuex;
    // 以上這些方法,都是返回純物件的.
    // mapState(['count', 'msg']) => { count() {} , msg() {}}
    const box = {
      template: `
        <div>
          <h3>box元件---{{num}}---{{str}}</h3>
          <button @click='$store.dispatch("asyncPlus", 1)'>box--count++</button>
          <button @click='$store.commit("reduce", 1)'>box--count--</button>
        </div>
      `,
      computed: {
        // count() {
        //   return this.$store.state.count
        // }
        // msg() {
        //   return this.$store.state.msg
        // }
        // ...mapState(['count', 'msg'])
        ...mapState({
          num: 'count',
          str: 'msg'
        })
      },
      methods: {
        ...mapActions(['asyncPlus']),
        ...mapMutations(['reduce'])
      }
    }

5.Vuex的計算屬性getters

  <script>
    const { mapState, mapMutations, mapGetters } = Vuex;
    const store = new Vuex.Store({
      state: {
        count: 1,
        price: 10,
      },
      // Vuex的計算屬性total
      getters: {
        total({count, price}) {
          return count * price
        }
      },
      mutations: {
        setCount(state, val) {
          state.count = val
        },
        setPrice(state, val) {
          state.price = val
        }
      }
    });
    const mx = {
      computed: {
        ...mapState(['count', 'price'])
      },
      methods: {
        ...mapMutations(['setCount', 'setPrice'])
      }
    }
    const count = {
      template: `<input type='text' placeholder='數量' :value='count' @input='setCount($event.target.value)' />`,
      mixins: [mx]
    }
    const price = {
      template: `<input type='text' placeholder='單價' :value='price' @input='setPrice($event.target.value)' />`,
      mixins: [mx]
    }
    const total = {
      template: `<div>總價:{{total}}</div>`,
      computed: {
        // total() {
        //   通過$store來獲取Vuex的計算屬性.
        //   return this.$store.getters.total
        // }
        // 通過對映方法快速引入Vuex的計算屬性total
        ...mapGetters(['total'])
      }
    }
    const App = {
      template: `
        <div>
          <count />
          <price />
          <total />
        </div>
      `,
      components: {count, price, total},
      store
    }
    new Vue({
      el: '#app',
      components: { App },
      template: `<App />`
    })
  </script>

6. Vuex的資料流

Vuex是如何讓多個元件同時更新的?

  1. 例項化Vuex的過程中,Vue會給state內的資料都新增資料劫持.
  2. 通過掛載store例項,就可以知道當state內的資料變化時,應該更新多少個元件.(收集依賴).
  3. 每當state內的資料變化,都會更新對應元件的檢視.

元件按鈕 => actions(dispatch) => mutations(commit) => state => 自動通知對應的檢視更新.

7. 總結

1:例項化,掛載
  new Vuex.Store({
    strict: true => 不允許在mutations之外修改資料
    state: {} => 多個元件共用的資料(狀態)
    mutations => 修改state內資料的邏輯
    actions => 非同步觸發mutations的方法
    getters => state的計算屬性
  });

  掛載 => 可以掛載到任意元件上.掛到new Vue上,就是全域性狀態管理.
  掛到元件A上,則A元件和A元件的所有子孫元素都可以共享Vuex的資料.

2:獲取資料
  $store.state.資料名
  computed: {
    資料名() {
      return this.$store.state.資料名
    }
  }

3:修改資料
  沒有非同步 => 直接commit觸發mutations
  有非同步 => 先通過dispatch觸發actions,actions再觸發mutations.  

4:對映
  mapState, mapMutations, mapActions, mapGetters