vue-------vuex状态管理器

状态管理器

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

并不需要把所有的组件的状态都放在状态管理器,但是它确实都可以放在状态管理器

  • 什么时候使用状态管理器?

来不同的视图需要依赖同一个状态
来自不同视图的行为需要变更同一个状态

每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)

  • Vuex 和单纯的全局对象有以下两点不同:
  1. Vuex 的状态存储是响应式的。
    当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
  2. 你不能直接改变 store 中的状态。
    改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用

状态管理器基本写法

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

Vue.use(Vuex)

const store = new Vuex.Store({
  state: { // 状态管理器管理的状态,罗列出来即可
    a: 1,
    b: 2,
    c: 3
  },
  mutations: { // 唯一改变状态的地方
    changeA (state) {
      state.a = '11'
    },
    changeB (state) {
      state.b = '22'
    },
    changeC (state, data) {
      state.c = data
    }
  }
})

export default store

4f8a8346a4fb7f59d65290daf867596f.png

  • 如何改变状态
import Vue from 'vue'import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: { // 状态管理器管理的状态,罗列出来即可
    a: 1,
    b: 2,
    c: 3
  },
  mutations: { // 唯一改变状态的地方
    changeA (state) {
      state.a = '11'
    },
    changeB (state) {
      state.b = '22'
    },
    changeC (state, data) {
      state.c = data
    },
    changeD (state, data) { // 传入对象  触发2种写法
      state.c = data.payload
    }
  }
})
console.log(store)
// 如果需要在组件中修改状态管理器状态,引入状态管理器,执行如下代码// store.commit('changeA')console.log(store.commit('changeA')) // undefined
store.commit('changeB')
store.commit('changeC', '333333333333333')
store.commit('changeD', { // 触发传入对象第一种写法
  payload: '4444444444'
})
store.commit({ // 触发传入对象第2种写法
  type: 'changeD',
  payload: '555555'
})
console.log(store.state)
export default store

  • 模拟真实场景 --- 异步操作在组件
import Vue from 'vue'import Vuex from 'vuex'import { getProlist } from '@/api'
Vue.use(Vuex)

const store = new Vuex.Store({
  state: { // 状态管理器管理的状态,罗列出来即可
    prolist: []
  },
  mutations: { // 唯一改变状态的地方
    changeProlist (state, data) {
      state.prolist = data.payload
    }
  }
})
console.log(store.state)
// 以下操作在组件中// 引入状态管理器
getProlist().then(res => {
  store.commit({
    type: 'changeProlist',
    payload: res.data.data
  })
  console.log(store.state)
})
export default store

  • 模拟真实场景 - 异步操作在状态管理器
import Vue from 'vue'import Vuex from 'vuex'import { getProlist } from '@/api'
Vue.use(Vuex)

const store = new Vuex.Store({
  state: { // 状态管理器管理的状态,罗列出来即可
    prolist: []
  },
  actions: { // 将组件的异步操作在此操作
    getProlistAction (context) { // context其实就类似于 this,其实就是当前的store
      // 如果获取到数据有后续操作,可以使用promise封装actions
      // getProlist().then(res => {
      //   context.commit({
      //     type: 'changeProlist',
      //     payload: res.data.data
      //   })
      // })
      // 比如你要上拉加载,下拉刷新,结束之后可以继续在组件中操作
      return new Promise((resolve, reject) => {
        getProlist().then(res => {
          context.commit({
            type: 'changeProlist',
            payload: res.data.data
          })
          resolve()
        })
      })
    }
  },
  mutations: { // 唯一改变状态的地方
    changeProlist (state, data) {
      state.prolist = data.payload
    }
  }
})
console.log(store.state)
// 组件中只需要 dispatch action即可 --- 简化了组件的代码,缩小组件的体积// store.dispatch('getProlistAction')// 上拉加载中页码 count ,有没有数据状态 finished 一般放在组件
store.dispatch('getProlistAction').then(() => {
  // 比如执行上拉加载中页码加1,拼接数据
})
export default store

8243dbb67fadad5b2ece6ccc7ef715b3.png

  • 状态管理器的计算属性
    ce58a7b1c53be4dc358903405ebfa49e.png
    b250d5ec232137b0b806bc818da7c24d.png
import Vue from 'vue'import Vuex from 'vuex'import { getProlist } from '@/api'
Vue.use(Vuex)

const store = new Vuex.Store({
  state: { // 状态管理器管理的状态,罗列出来即可
    prolist: []
  },
  getters: { // 计算属性
    getProlistLen (state) {
      return state.prolist.length
    }
  },
  actions: { // 将组件的异步操作在此操作
    getProlistAction (context) { // context其实就类似于 this,其实就是当前的store
      // 如果获取到数据有后续操作,可以使用promise封装actions
      // getProlist().then(res => {
      //   context.commit({
      //     type: 'changeProlist',
      //     payload: res.data.data
      //   })
      // })
      // 比如你要上拉加载,下拉刷新,结束之后可以继续在组件中操作
      return new Promise((resolve, reject) => {
        getProlist().then(res => {
          context.commit({
            type: 'changeProlist',
            payload: res.data.data
          })
          resolve()
        })
      })
    }
  },
  mutations: { // 唯一改变状态的地方
    changeProlist (state, data) {
      state.prolist = data.payload
    }
  }
})
console.log(store.state)
// 组件中只需要 dispatch action即可 --- 简化了组件的代码,缩小组件的体积// store.dispatch('getProlistAction')// 上拉加载中页码 count ,有没有数据状态 finished 一般放在组件
store.dispatch('getProlistAction').then(() => {
  // 比如执行上拉加载中页码加1,拼接数据
  // 获取计算属性的值
  console.log(store.getters)
})
export default store

  • 为了状态管理器的方便管理,会划分模块 -- 按照功能
import Vue from 'vue'import Vuex from 'vuex'
Vue.use(Vuex)

const moduleA = {
  state: {
    a: 1
  },
  mutations: {
    changeA (state) {
      state.a = '111'
    }
  }
}

const moduleB = {
  state: {
    b: 2
  },
  mutations: {
    changeB (state) {
      state.b = '222'
    }
  }
}

const moduleC = {
  state: {
    c: 3
  },
  mutations: {
    changeC (state) {
      state.c = '333'
    }
  }
}

// 加入有非常多个状态,我们放在一起管理,维护代价太高// 模块化 --- 功能 、 页面 、组件// 功能 - 登陆、注册、用户的各种状态 / 购物车相关 / 分类 / 搜索// 每一个功能模块 都至少有 state 和 mutations,可以含有 actions和getters// 创建状态管理器时整合 功能模块const store = new Vuex.Store({
  modules: {
    moduleA,
    moduleB,
    moduleC
  }
})
console.log(store)
console.log(store.state) // 拿到所有的状态  ----  对象模式console.log(store.state.moduleA.a) // 获取moduleA模块中的状态// 改变状态  ---- 唯一改变状态的方式就是显示的提交mutation// 提交的 mutation 不分模块,相当于把所有的mutations放到了一起
store.commit('changeA')
console.log(store.state.moduleA.a)
export default store

478a565228a34a8c7804e7264cbda7aa.png

  • 如果两个模块中的 mutations 重名怎么办?

模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。

import Vue from 'vue'import Vuex from 'vuex'
Vue.use(Vuex)
// 模块中的mutations其实最后是不分的,多个模块可能存在重名的情况 ---- 每个模块添加一个命名空间const moduleA = {
  namespaced: true,
  state: {
    a: 1
  },
  mutations: {
    changeA (state) {
      state.a = '111'
    }
  }
}

const moduleB = {
  namespaced: true,
  state: {
    b: 2
  },
  mutations: {
    changeB (state) {
      state.b = '222'
    }
  }
}

const moduleC = {
  namespaced: true,
  state: {
    c: 3
  },
  mutations: {
    changeC (state) {
      state.c = '333'
    }
  }
}

// 加入有非常多个状态,我们放在一起管理,维护代价太高// 模块化 --- 功能 、 页面 、组件// 功能 - 登陆、注册、用户的各种状态 / 购物车相关 / 分类 / 搜索// 每一个功能模块 都至少有 state 和 mutations,可以含有 actions和getters// 创建状态管理器时整合 功能模块const store = new Vuex.Store({
  modules: {
    moduleA,
    moduleB,
    moduleC
  }
})
console.log(store)
console.log(store.state) // 拿到所有的状态  ----  对象模式console.log(store.state.moduleA.a) // 获取moduleA模块中的状态// 改变状态  ---- 唯一改变状态的方式就是显示的提交mutation// 提交的 mutation 不分模块,相当于把所有的mutations放到了一起
store.commit('moduleA/changeA')
console.log(store.state.moduleA.a)
export default store

63d7e4ba08420a3364a2f3e3c400dd93.png
920ea67d31591a71288b6ac0a98bc2c4.png

  • 模拟组件
import Vue from 'vue'import Vuex from 'vuex'import { getProlist, getCategoryBrandList } from '@/api'
Vue.use(Vuex)
// 模块中的mutations其实最后是不分的,多个模块可能存在重名的情况 ---- 每个模块添加一个命名空间const home = {
  namespaced: true,
  state: {
    list: []
  },
  actions: {
    getListAction ({ commit }) {
      return new Promise(resolve => {
        getProlist().then(res => {
          commit({
            type: 'changeList',
            payload: res.data.data
          })
          resolve()
        })
      })
    }
  },
  mutations: {
    changeList (state, data) {
      state.list = data.payload
    }
  }
}

const kind = {
  namespaced: true,
  state: {
    list: []
  },
  actions: {
    getListAction ({ commit }) {
      return new Promise(resolve => {
        getCategoryBrandList({
          type: '手机',
          brand: 'huawei'
        }).then(res => {
          commit({
            type: 'changeList',
            payload: res.data.data
          })
          resolve()
        })
      })
    }
  },
  mutations: {
    changeList (state, data) {
      state.list = data.payload
    }
  }
}

const store = new Vuex.Store({
  modules: {
    home,
    kind
  }
})

// 模拟组件操作
store.dispatch('home/getListAction').then(() => {
  console.log('home', store.state.home)
})
store.dispatch('kind/getListAction').then(() => {
  console.log('kind', store.state.kind)
})
export default store

  • 如果异步操作用于actions中,但是触发acitons时,如果需要传递参数呢?
import Vue from 'vue'import Vuex from 'vuex'import { getProlist, getCategoryBrandList } from '@/api'
Vue.use(Vuex)
// 模块中的mutations其实最后是不分的,多个模块可能存在重名的情况 ---- 每个模块添加一个命名空间const home = {
  namespaced: true,
  state: {
    list: []
  },
  actions: {
    getListAction ({ commit }, params) {
      console.log('params', params)
      return new Promise(resolve => {
        getProlist(params).then(res => {
          commit({
            type: 'changeList',
            payload: res.data.data
          })
          resolve()
        })
      })
    }
  },
  mutations: {
    changeList (state, data) {
      state.list = data.payload
    }
  }
}

const kind = {
  namespaced: true,
  state: {
    list: []
  },
  actions: {
    getListAction ({ commit }) {
      return new Promise(resolve => {
        getCategoryBrandList({
          type: '手机',
          brand: 'huawei'
        }).then(res => {
          commit({
            type: 'changeList',
            payload: res.data.data
          })
          resolve()
        })
      })
    }
  },
  mutations: {
    changeList (state, data) {
      state.list = data.payload
    }
  }
}

const store = new Vuex.Store({
  modules: {
    home,
    kind
  }
})

// 模拟组件操作
store.dispatch('home/getListAction', { count: 1, limit: 15 }).then(() => {
  console.log('home', store.state.home)
})
store.dispatch('kind/getListAction').then(() => {
  console.log('kind', store.state.kind)
})
export default store

1b1aa0da38757b9497908779d7f7c945.png
0c7362791633647e0516b482443b2150.png

  • 使用常量替代 Mutation 事件类型 - AC
    d0b72403425e9459b02c19b1860c26c9.png
import Vue from 'vue'import Vuex from 'vuex'import { getProlist, getCategoryBrandList } from '@/api'import { CHANGE_LIST } from './mutation-types'
Vue.use(Vuex)

// 使用常量代替mutations// 使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名const home = {
  namespaced: true,
  state: {
    list: []
  },
  actions: {
    getListAction ({ commit }, params) {
      console.log('params', params)
      return new Promise(resolve => {
        getProlist(params).then(res => {
          commit({
            type: CHANGE_LIST,
            payload: res.data.data
          })
          resolve()
        })
      })
    }
  },
  mutations: {
    [CHANGE_LIST] (state, data) {
      state.list = data.payload
    }
  }
}

const kind = {
  namespaced: true,
  state: {
    list: []
  },
  actions: {
    getListAction ({ commit }) {
      return new Promise(resolve => {
        getCategoryBrandList({
          type: '手机',
          brand: 'huawei'
        }).then(res => {
          commit({
            type: CHANGE_LIST,
            payload: res.data.data
          })
          resolve()
        })
      })
    }
  },
  mutations: {
    [CHANGE_LIST] (state, data) {
      state.list = data.payload
    }
  }
}

const store = new Vuex.Store({
  modules: {
    home,
    kind
  }
})

// 模拟组件操作
store.dispatch('home/getListAction', { count: 1, limit: 20 }).then(() => {
  console.log('home', store.state.home)
})
store.dispatch('kind/getListAction').then(() => {
  console.log('kind', store.state.kind)
})
export default store

aca6f047bef7309b8eaa7d76bb14f3a6.png
a6da8480cdcee5c39208caaa0d14fe44.png
cbe0c955ea949a99c05ed9bd9afc7cf6.png

项目中使用状态管理器

登陆状态相关

4f1b123f17c158017b89854be171fa1a.png
0a8cfd11507c74b623dede001f539f04.png
d62ec220a0a459db07ebf338239fc125.png
83e5dd003cc4a06e422f88b46fce20af.png
b28dcc98ebd7300bf451b8b7aece3a5e.png
3e3aaef90cceffb894bd19b08d759e57.png
4ca2bae0285a6711b24b66daffd383a0.png

底部组件中判定登陆状态
632081def0448369d42faf29bd5a7e10.png
首页头部需要判定
cc416f7975321d58e47facb76c67d212.png

登陆页面修改登陆的业务逻辑
7ec49440da2f2d66a38880a5569ff071.png

上图有坑

个人中心显示登陆还是注册
4acdb8f59ee934a74acc744dd99e772d.png

 

-----------------------------------------------------文章来自吴大勋(大勋说)链接

posted @ 2020-04-19 15:55  haccer  阅读(83)  评论(0编辑  收藏  举报