个人自学前端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
上一篇:关于vueX如何定义和使用


下一篇:vuex使用