Vue学习-Vuex状态管理

Vue学习-Vuex状态管理

可以理解为:多个组件共享的变量全部存储在一个对象里面,然后将这个对象放在顶层的Vue实例中,让其他组件可以使用—集中式状态管理

自己封装的对象不是响应式的(Vue.prototype.shareObj

官网: Vuex 是什么? | Vuex (vuejs.org)

管理什么状态?

  • 比如用户的登录状态、用户名称、头像、地理位置信息等等

  • 比如商品的收藏、购物车中的物理等等

  • 这些状态信息,我们都可以放在统一的地方,对它进行保存和管理,而且它们还是响应式的

Vuex-单界面到多界面的状态切换

单界面

单界面的状态管理.png

多界面

多界面的状态管理.png

Demo

index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    // 存放共享的状态
    state: {
        counter: 1000
    },
    // 修改共享的状态方法
    mutations: {
        // 默认有参数state
        increment(state) {
            state.counter++;
        },
        decrement(state) {
            state.counter--;
        }
    },
    actions: {},
    getters: {

    },
    modules: {}
})
复制代码

App.vue

<template>
  <div id="app">
    <h2>{{ message }}</h2>
    <h2>{{ $store.state.counter }}</h2>
    <button @click="addition">+</button>
    <button @click="substraction">-</button>

    <hr>
    <h2>HelloVuex</h2>
    <hello-vuex></hello-vuex>
  </div>
</template>

<script>
import HelloVuex from './components/HelloVuex';

export default {
  name: 'App',
  data() {
    return {
      message: '我是App组件'
    }
  },
  components: {
    HelloVuex
  },
  methods: {
    addition() {
      // 调用increment函数
      this.$store.commit('increment');
    },
    substraction() {
      // 调用decrement函数
      this.$store.commit('decrement');
    }
  }
}
</script>

<style>
</style>

复制代码

HelloVuex

<!--  -->
<template>
  <div>
      {{ this.$store.state.counter }}
  </div>
</template>

<script>
export default {
  data () {
    return {
    };
  }
}

</script>
<style lang='stylus' scoped>
</style>
复制代码

Vuex核心概念

State

单一状态树(单一数据源)

只创建一个store对象

Getters (类似于计算属性)

基本使用

getters: {
    powerCounter(state) {
        return state.counter * state.counter;
    }
}
复制代码
{{ $store.getters.powerCounter }}
复制代码

getters作为参数

getters: {
    powerCounter(state) {
            return state.counter * state.counter;
        },
        more20Stu(state) {
            return state.students.filter(s => s.age >= 20);
        },
        more20StuLength(state, getters) {
            return getters.more20Stu.length;
        },
        // 直接返回一个函数
        moreAgeStu(state) {
            return function(age) {
                return state.students.filter(s => s.age >= age).length;
            }
        }
}
复制代码

Mutations-状态更新

  • Vuex的store状态的更新唯一方式:提交Mutation
  • Mutation主要包括两部分:
    • 字符串的事件类型(type)
    • 一个回调函数(handler),该回调函数的第一个参数就是state

携带参数

// 修改共享的状态方法
mutations: {
    // 默认有参数state
    increment(state) {
        state.counter++;
    },
    decrement(state) {
        state.counter--;
    },
    // 携带参数
    incrementCount(state, count) {
        state.counter += count;
    }
},
复制代码
addCount(count) {
    this.$store.commit('incrementCount', count)
}
复制代码

提交风格

this.$store.commit({
    type: 'incrementCount',
    count: 5
})
复制代码
incrementCount(state, payLoad) {
    state.counter += payLoad.count;
}
复制代码

Vuex数据的响应原理

  • Vuex的store中的state是响应式的,当state中的数据发生改变时,Vue组件会自动更新

    • 要求state中的数据初始化过的,如果没有初始化,则不会响应式

    • info: {
          name: 'aaa',
          age: 40,
          height: 1.98
      }
      复制代码
    • updateInfo(state) {
          // state.info.name = 'bbb'; // 响应式
          state.info['address'] = 'chengdu'; // 非响应式,没有初始化
      }
      复制代码
  • 解决办法

    Vue.set(state.info, 'address', 'chengdu');
    复制代码
  • 删除对象属性

    delete state.info.age; // 不是响应式
    Vue.delete(state.info, 'age'); // 响应式
    复制代码

Actions-异步

异步方式修改state放在Actions,不要放在mutations中

actions: {
    // context: 上下文
    aUpdateInfo(context, payLoad) {
        setTimeout(() => {
            // mutations中的方法 
            context.commit('updateInfo');
            console.log(payLoad);
        }, 1000)
    }
},
复制代码
updateInfo() {
    // this.$store.commit('updateInfo');
 	// 这里使用dispatch而不是commit
    this.$store.dispatch('aUpdateInfo', '我是payLoad')
}
复制代码

通知外部回调完成

方法1:

actions: {
    // context: 上下文
    aUpdateInfo(context, payLoad) {
        setTimeout(() => {
            context.commit('updateInfo');
            console.log(payLoad);
            console.log(payLoad.message);
            payLoad.success();
        }, 1000);
    }
}
复制代码
updateInfo() {
    // this.$store.commit('updateInfo');
    this.$store.dispatch('aUpdateInfo', {
        message: '我是携带的信息',
        success: () => {
            console.log('里面的已经完成了')
        }
    })
}
复制代码

优雅的方式2:

aUpdateInfo(context, payLoad) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            context.commit('updateInfo');
            console.log(payLoad);
            // console.log(payLoad.message);
            // payLoad.success();
            resolve('success');
        }, 1000);
    })
}
复制代码
updateInfo() {
    // this.$store.commit('updateInfo');
    // this.$store.dispatch('aUpdateInfo', {
    //   message: '我是携带的信息',
    //   success: () => {
    //     console.log('里面的已经完成了')
    //   }
    // })
    this.$store.dispatch('aUpdateInfo', '我是携带的信息')
        .then((res) => {
        console.log('外部' + res);
    })
}
复制代码

Modules

单一状态树只能创建一个store,modules可以创建不同的模块,不同的模块中可以创建store(套娃)

const moduleA = {
    state: {
        name: 'zhangsan'
    },
    mutations: {
        updateName(state, payLoad) {
            state.name = payLoad;
        }
    },
    actions: {
        aUpdateNameA(context) {
            setTimeout(() => {
                context.commit('updateName', 'wangwu')
            }, 1000);
        }
    },
    getters: {
        fullname(state) {
            return state.name + '1111';
        },
        fullname2(state, getters) {
            return getters.fullname + '222';
        },
        fullname3(state, getters, rootstate) {
            return getters.fullname2 + rootstate.counter;
        }
    }
}

const moduleB = {
    state: {
        name: 'lisi'
    },
    mutations: {

    },
    actions: {

    },
    getters: {

    }
}
复制代码
modules: {
    a: moduleA,
    b: moduleB
}
复制代码
<h2>{{ $store.state.a.name }}</h2>
<h2>{{ $store.state.b.name }}</h2>
<h2>{{ $store.getters.fullname }}</h2>
<h2>{{ $store.getters.fullname2 }}</h2>
<h2>{{ $store.getters.fullname3 }}</h2>

<button @click="updateName">修改名字</button>
<button @click="aUpdateNameA">异步修改名字</button>
复制代码
updateName() {
    this.$store.commit('updateName', 'fawaikuangtu');
},
aUpdateNameA() {
    this.$store.dispatch('aUpdateNameA');
}
复制代码

项目结构

将index.js中的文件抽取为对应的模块,然后在index.js中导入对应的模块

├── index.html
├── main.js
├── api
│   └── ... # 抽取出API请求
├── components
│   ├── App.vue
│   └── ...
└── store
    ├── index.js          # 我们组装模块并导出 store 的地方
    ├── actions.js        # 根级别的 action
    ├── mutations.js      # 根级别的 mutation
    └── modules
        ├── cart.js       # 购物车模块
        └── products.js   # 产品模块
复制代码

vuex模块化.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享