Vuex状态管理

简介

Vuex用作共享状态管理或者复杂跨组件通信(非父子组件)。共享状态管理如登录状态、用户信息、购物车等等。包含以下属性:

  • State:vuex 状态管理的数据源,就是一个 json 数据。
  • Getter:Getter 的作用与 filters 有一些相似,可以将 State 进行过滤后输出。
  • Mutation:Mutaion 是 vuex 中改变 State 的唯一途径(严格模式下),并且只能是同步操作。
  • Action:对 State 的异步操作可放在 Action 中,并通过在 Action 提交 Mutaion 变更状态。
  • Module:当 Store 对象过于庞大时,可根据具体的业务需求分为多个 Module。

规则

Vuex 不限制代码结构,但是它规定了规则:

  • 状态集中到单个 store 对象中。
  • 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
  • 异步逻辑封装到 action 中。

官方示例购物车的项目结构(大型结构)。小应用代码可以统一写在store/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
/*
*store里外层的action.js/mutations.js是整体公共状态
*modules里是不同模块的状态集成,也包含了state、getters、mutations、actions
*/

使用示例

在 store/index.js 中封装 store 。state 中加共享的数据,getter 过滤数据稍后在其他页面使用,mutations 处理需要修改的情况( commit 提交)和缓存数据,actions 处理异步数据dispatch提交给 mutations ,mutations 再 commit。

//store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        islogin: 0, //登录状态 0未登录 1已登陆
        userInfo: '' || JSON.parse(localStorage.getItem('userInfo'))
    },
    getters: {
        userInfo: (state) => state.userInfo,
        doneTodos: (state, getters) => {
            return getters.doneTodos.length
        }
    },
    mutations: {
        //修改
        setUserInfo: (state, userInfo) => {
           state.userInfo = userInfo
           localStorage.setItem('userInfo', JSON.stringfy(userInfo))
        },
        setLoginStatus:(state,islogin) => {state.islogin = islogin}
    },
    actions: {
        changeInfo(context) {
         // 可以包含异步操作
        // context 是一个与 store 实例具有相同方法和属性的 context 对象
        }
    }
});
export default store
//main.js
import store from './store'

const user_token = ''|| localStorage.getItem('token');
if (user_token) {
      // 提交修改
      store.commit('setLoginStatus', '1');
  }
}
//login.vue部分代码
if(res.meta.status === 200){
     // 提示登录成功
    this.$message({
         message: res.meta.msg,
         type: 'success'
    });
    localStorage.setItem('token',res.data.token);
    // 提交修改
    this.$store.commit('setUserInfo',res.data.user);
}
//user.vue
您好,{{$store.getters.userInfo.username}}

State

需要修改的状态,需要在使用状态创建计算属性,这样当state修改之后能够更新。或者getter处理获取(getter带有计算属性)。




//直接用$store.getters


Getter

过滤state的数据,处理后在供其他地方应用。具有计算属性一样的特质,只有state改变才会再次触发。
Getter 方法也接受 state 和其他 getters 作为前两个参数。接受getters下其他方法过滤过的数据,再次进行处理。如下

 getters: {
        userInfo: (state) => state.userInfo,
        weekDate: state => {
            return moment(state.date).format('dddd'); 
        },
        doneTodos: (state, getters) => {
            return getters.weekDate.length//接受的其他 getter
        }
    }

mutations

mutations里的函数有两个参数 state 和 payload 。payload 是载荷也就是提交值。

mutations: {
        //修改
    setLoginStatus:(state,islogin) => {state.islogin = islogin}
}
//login.vue
store.commit('setLoginStatus', '1');

Action

  • Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。
  • actions 用 dispatch 提交。

其他地方使用actions里的方法用dispatch提交,在actions方法中commit给state。这就是它为啥自带跟store一样功能的context。

//store/index.js
actions: {
    // 登录
    Login({commit}, userInfo) {
      return new Promise((resolve, reject) => {
        login(userInfo.account, userInfo.password).then(res => {
          if(res.status==200){
            const tokenSuccess = aa.data.token.tokenValue
            commit('SET_TOKEN', tokenSuccess )
            document.cookie=`cookie地址`;
            token="test"+tokenSuccess ;
            //setToken("test" +token)
            resolve(res.data)
          } 
        }).catch(error => {
          console.log("登录失败")
          reject(error)
        })
      })
    },
  }

//**.vue
toLogin() {
   this.$store.dispatch('Login',arg).then(() => {
           
    })
}
以下是action常用场景

store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise。三种方式使用:
1.直接处理数据提交给state,在其他页面使用state。(组件共享数据)

state: {
    userList: [],
},
mutations: {
    // 简化mutatios的代码量
    updateData(state, data) {
        state[data.key] = data.value;
    }
},
actions:{      
   getUserList: async function(contex) {
        let value = await axios('you api url').then(res => res.data);
        contex.commit("updateData", {
            key: "userList",
            value
        });
    }
 }

2.将返回promise获取数据不提交给state,其他页面使用action。(组件共享方法)

// actions.js
getUserList: async function(contex) {
    let value = await axios('you api url').then(res => res.data);
    return value;
}

// ***.vue
methods:{
    ...mapActions(["getUserList"]),
    getData(){
        const userList = this.getUserList();
        // 后续的处理
    }
}

3.获取返回的promise不提交给state,其他页面先获取数据使用action。(组件共享方法)

// actions.js
getUserList(contex) {
    return axios('you api url').then(res => res.data);
}

// ***.vue

methods:{
    ...mapActions(["getUserList"]),
    getDataSync:async function(){
        const data = await this.getUserList().then(res=>res.data);
        // 后续的处理
    }
}

Module

[了解更多]
(https://blog.csdn.net/AiHuanhuan110/article/details/89184259#t7)
就是分很多个modules,每个 module 包含一套state/getters/mutations/action,state状态为模块内部共享状态。使用起来就是this.$store.a.state多了一层,还是一样的方法,就是从外层逻辑上分块了而已。

const moduleA = {
 state: { ... },
 mutations: { ... },
 actions: { ... },
 getters: { ... }
 }
const moduleB = {
 state: { ... },
 mutations: { ... },
 actions: { ... }
 }
 
const store = new Vuex.Store({
 modules: {
  a: moduleA,
  b: moduleB})

mapState、mapGetters、mapMutations、mapActions

import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'

export default {
    // ...
    computed: {
      localComputed () { /* ... */ },
      ...mapState({
        // 为了能够使用 `this` 获取局部状态,必须使用常规函数
        count(state) {
          return state.count + this.localCount
        }
      }),
      ...mapGetters({
        getterCount(state, getters) {
          return state.count + this.localCount
        }
      })
    }
    methods: {
      ...mapMutations({
          // 如果想将一个属性另取一个名字,使用以下形式。注意这是写在对象中
          add: 'increment' // 将 `this.add()` 映射为`this.$store.commit('increment')`
      }),
      ...mapActions({
          add: 'increment' 
      })
    }
}
//都可映射为以下数组样式,使用直接this.xxx即可
methods: {
    ...mapActions(['increment', 'incrementBy' ]),
}

你可能感兴趣的:(Vuex状态管理)