了解Vuex状态管理模式的理解强化指南

42次阅读

共计 13301 个字符,预计需要花费 34 分钟才能阅读完成。

1

Vuex 是什么呢?它是 Vue 的状态管理模式,在使用 vue 的时候,需要在 vue 中各个组件之间传递值是很痛苦的,在 vue 中我们可以使用 vuex 来保存我们需要管理的状态值,值一旦被改变,所有引用该值的地方就会自动更新。是不是很方便,很好用呢?

vuex 是专门为 vue.js 设计的状态管理模式,集中式存储和管理应用程序中所有组件的状态,vuex 也集成了 vue 的官方调式工具,一个 vuex 应用的核心是 store,一个容器,store 包含了应用中大部分状态。

那么我们在什么时候应用 vuex 呢?vuex 也不是随便乱用的,小型简单的应用就不那么合适了,因为用了 Vuex 是繁琐多余的,更适合使用简单的 store 模式;对于 vuex 更加适用于中大型单页应用:多个视图使用于同一状态,不同视图需要变更同一状态。

传参的方法对于多层嵌套的组件来说,是非常繁琐的,并且对于兄弟组件间的状态传递无能为力;采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝,通常会导致无法维护的代码。

npm install vuex --save //yarn add vuex
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

在创建 vuex 实例的地方引入 vue,vuex

import Vue from 'vue'// 引入 vue
import Vuex from 'vuex'// 引入 vuex

Vue.use(Vuex); // 使用 vuex

import store from './store' // 引入状态管理 store

new 一个 Vuex.Store 实例,并注册 state,mutations,actions,getters 到 Vuex.Store 实例中:

import Vue from 'vue';
import Vuex from 'vuex'; // 引入 vuex
import store from './store' // 注册 store

Vue.use(Vuex); // 使用 vuex

export default new Vuex.Store({state: {...},
 mutations: {...},
 actions: {...},
 getters: {...}
})

// 当代码量大额时候写个 js 文件即可
store
action.js
index.js
mutation.js
// 引入到 store/index.js 注册到 vuex 实例中
import mutations from './mutations' // 引入 mutations
import actions from './action' // 引入 action
import Vue from 'vue' // 引入 vue
import Vuex from 'vuex' // 引入 vuex

Vue.use(Vuex);
// 创建 state
const state = {count: 0};

export default new Vuex.Store({
 state, // 注册 state
 action, // 注册 actions
 mutations // 注册 mutations
})

创建好 vuex.store 后,需要在入口文件 main.js 中引入 store 并注册到 vue 实例中,这样就可以在任何组件使用 store 了。

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store' // 引入状态管理 store

Vue.config.productiontip = false
new Vue({
 router,
 store, // 注册 store
 render: h => h(App)
}).$mount('#app')

在组件中使用,引入 vuex 中各属性对应的辅助函数:

import {mapActions, mapState,mapGetters} from 'vuex' 
// 注册 action、state、getter

2

创建一个 vue 项目,输入 vue int webpack web,安装 vuex,命令:npm install vuex –save。

store,index.js

import Vue from 'vue' // 引入 vue
import Vuex from 'vuex' // 引入 vuex
// 使用 vuex
Vue.use(Vuex);
// 创建 Vuex 实例
const store = new Vuex.store({})
export default store // 导出 store

main.js

import Vue from 'Vue'
import App from './App'
import router from './router'
import store from '.store'

Vue.config.productiontip = false

new Vue({
 el: '#app',
 store,
 router,
 components: {App},
 ...
})

State,可以在页面通过 this.$store.state 来获取我们定义的数据:

import Vue from 'vue' // 引入 vue
import Vuex from 'vuex' // 引入 vuex
// 使用 vuex
Vue.use(Vuex);

// 创建 Vuex 实例:const store = new Vuex.Store({
 state: {count: 1}
})
export default store // 导出 store
{{this.$store.state.count}}

Getters 相当于 vue 中的 computed 计算属性,getter 的返回值根据它的依赖被缓存起来,且只有当它的依赖值发生改变时才会重新计算。

Getters 可以用于监听,state 中的值的变化,返回计算后的结果。

{{this.$store.getSateCount}}
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({
 state: {count: 1;},
 getters: {getStateCount: function(state){return state.count+1;}
 }

Mutations

{{this.$store.state.count}}
<button @click="addFun">+</button>
<button @click="reductionFun">-</button>

methods: {addFun() {this.$store.commit("add");
 },
 reductionFun() {this.$store.commit("reduction");
 }
}

index.js

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
// 创建 Vuex 实例
const store = new Vuex.store({
 state: {count: 1},
 getters: {getStateCount: function(state){return state count+1;}
 },
 mutations: {add(state) {state.count = state.count+1;},
  reduction(state){state.count = state.count-1;}
 }
})
export default store // 导出 store

Actions:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({
 state: {count: 1;},
 getters: {getStateCount: function(state){return state.count+1;}
 }
 mutations: {add(state) {state.count = state.count+1;},
  reduction(state) {state.count = state.count-1;}
 },
 actions: {addFun(context) {context.commit("add");
  },
  reductionFun(context) {context.commit("reduction");
  }
 }
// vue
methods: {addFun() {this.$store.dispatch("addFun");
  // this.$store.commit("add");
 },
 reductionFun() {this.$store.dispatch("reductionFun");
 }
}

传值:

methods: {addFun() {this.$store.dispatch("addFun");
  // this.$store.commit("add");
 },
 reductionFun() {
  var n = 10;
  this.$store.dispatch("reductionFun", n);
 }
}
 mutations: {add(state) {state.count = state.count+1;},
  reduction(state,n) {state.count = state.count-n;}
 },
 actions: {addFun(context) {context.commit("add");
  },
  reductionFun(context,n) {context.commit("reduction",n);
  }
 }

mapState、mapGetters、mapActions

this.$stroe.state.count
this.$store.dispatch('funName')
<div style="border:1px solid red; margin-top: 50px;">
 {{count1}}
</div>

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

computed: {
 ...mapState({count1:state=> state.count})
}

3

state 是最底层的初始数据,getters 就相当于 vue 中的计算属性,是对 state 数据进行处理和扩展的,mutations 是当需要修改 state 时,定义的 mutations,actions 时当需要很多很多的 mutations 进行处理时,在 actions 进行 mutations 派发的,异步处理也是在这里定义的。

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

那么状态管理模式是怎样的书写格式:

new Vue({
 // state 初始状态(数据)data() {
  return {count: 0}
 },
 template: `<div>{{count}}</div>`,
 methods: {increment() {this.count++}
 }
})

多个数组共享状态时:

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

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {  // 状态
    count: 0
  },
  mutations: {  // 变化
    increment (state) {state.count++}
  }
})
store.commit('increment')

state 初始状态,getter 相当于计算属性,mutation 状态变更,action 行动,module 模块。

Vue.use(Vuex)

const app = new Vue({
  el: '#app',
  store,
  components: {Counter},
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
})
import {mapState} from 'vuex'

export default {
  // ...
  computed: mapState({
    // 箭头函数可使代码更简练
    count: state => state.count,

    // 传字符串参数 'count' 等同于 `state => state.count`
    countAlias: 'count',

    // 为了能够使用 `this` 获取局部状态,必须使用常规函数
    countPlusLocalState (state) {return state.count + this.localCount}
  })
}
computed: mapState([
  // 映射 this.count 为 store.state.count
  'count'
])

getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

const store = new Vuex.Store({

  state: {
    todos: [{ id: 1, text: '...', done: true},
      {id: 2, text: '...', done: false}
    ]
  },
  
  getters: {
    doneTodos: state => {return state.todos.filter(todo => todos.done)
    }
  }
  
})
getters: {
  // ...
  doneTodosCount: (state, getters) => {return getters.doneTodos.length}
}

store.getters.doneTodosCount // -> 1

mapGetters 辅助函数是将 store 中的 getter 映射到局部计算属性

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation

mutations: {increment (state, n) {state.count += n}
}

store.commit('increment', 10)

this.$store.commit(‘xxx’) 提交 mutation

mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用

import {mapMutations} from 'vuex'
export default {
  methods: {
  
    ...mapMutations([
      'increment',
      // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
      // `mapMutations` 也支持载荷:'incrementBy' 
      // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
    ]),
    
  this.incrementBy(); 调用
  
    ...mapMutations({
      add: 'increment' 
      // 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
    
  }

}

Action 提交的是 mutation 变化,而不是直接变更状态。Action 可以包含任意异步操作。

store.dispatch('increment')

使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用

import {mapActions} from 'vuex'

export default {
  // ...
  methods: {
  
    ...mapActions([
      'increment', 
      // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`

      // `mapActions` 也支持载荷:'incrementBy' 
      // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    
    ...mapActions({
      add: 'increment' 
      // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }
}

vue

安装 vue-cli
cnpm install -g vue-cli

安装 webpack 模板 :
vue init webpack myProject

安装依赖
cnpm install

安装路由
cnpm install vue-router –save-dev

安装 axios http
cnpm install axios –save

4

vue 和单纯的全局对象区别:

vuex 的状态存储时响应式的,改变 store 中的状态的唯一途径就是显式地提交 commit, mutation。

Vuex 的核心是 store,store 包含着应用中大部分的状态 (state)。

一个最简单的 store 包含 state 与 mutation,可以通过 store.state 来获取状态对象,以及通过 store.commit 方法触发状态变更。

State,存储着应用中的所有基础“全局对象”,this.$store.state.XXX 可访问到。
mapState:使用此辅助函数帮助我们生成计算属性,获得多个 state 值。

Getter 从 store 中的 state 中派生出一些状态,接受 state 作为第一个参数,第二个参数可传值计算,会暴露为 store.getters 对象,可以以属性的形式访问这些值。

Vuex 中的 mutation,每个 mutation,事件类型 (type) 和 一个 回调函数 (handler)

Action 提交的是 mutation,不是直接变更状态,可以包含任意异步操作,通过 store.dispatch 方法触发。

5

vuex 的出现是为了解决哪些问题呢?我们知道在组件之间的作用域是独立的父组件和子组件的通讯可以通过 prop 属性来传参,但是兄弟组件之间通讯就不那么友好了。

首先要告诉它们的父组件,然后由父组件告诉其他组件,一旦组件很多很多的时候,通讯起来就不方便了,vuex 解决了这个问题,让多个子组件之间可以方便的通讯。

|-store/ // 存放 vuex 代码
| |-actions.js
| |-getters.js
| |-index.js
| |-mutations.js
| |-state.js
|-store/ // 存放 vuex 代码
| |-Module1
| | |-actions.js
| | |-getters.js
| | |-index.js
| | |-mutations.js
| | |-state.js
| |-Module2
| | |-actions.js
| | |-getters.js
| | |-index.js
| | |-mutations.js
| | |-state.js
| |-index.js // vuex 的核心,创建一个 store

vuex 是什么?

Vuex 是一个专门为 vue.js 应用程序开发的状态管理模式,它是采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调式工具 devtools extension,提供了诸如零配置的 time-travel 调试,状态快照导入导出等高级调试功能。

什么是“状态管理模式”?

new Vue({

  // state
  data () {
    return {count: 0}
  },
  
  // view
  template: `
    <div>{{count}}</div>
  `,
  
  // actions
  methods: {increment () {this.count++}
  }
  
})

state,驱动应用的数据源;
view,以声明方式将 state 映射到视图;
actions,响应在 view 上的用户输入导致的状态变化。

我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:

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

核心概念:State,Getter,Action,Module

Vuex 和单纯的全局对象有以下两点不同:

1.Vuex 的状态存储是响应式的。
2. 不能直接改变 store 中的状态。

创建一个 store

// 如果在模块化构建系统中,请确保在开头调用了 Vue.use(Vuex)

const store = new Vuex.Store({

  state: {count: 0},
  
  mutations: {increment (state) {state.count++}
  }
  
})

通过 store.state 来获取状态对象,通过 store.commit 方法触发状态变更

store.commit('increment')

console.log(store.state.count) // -> 1

用一个对象包含了全部的应用层级状态,每个应用将仅仅包含一个 store 实例。单一状态树。Vuex 的状态存储是响应式的,读取状态方法,即是在计算属性中返回。

// 创建一个 Counter 组件

const Counter = {template: `<div>{{ count}}</div>`,
  computed: {count () {return store.state.count}
  }
}

Vuex 通过 store 选项

const app = new Vue({
  el: '#app',
  // 把 store 对象提供给“store”选项,这可以把 store 的实例注入所有的子组件
  store,
  components: {Counter},
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
})


const Counter = {template: `<div>{{ count}}</div>`,
  computed: {count () {return this.$store.state.count}
  }
}

使用 mapState 辅助函数帮助我们生成计算属性

// 在单独构建的版本中辅助函数为 Vuex.mapState
import {mapState} from 'vuex'

export default {
  // ...
  computed: mapState({
    // 箭头函数可使代码更简练
    count: state => state.count,

    // 传字符串参数 'count' 等同于 `state => state.count`
    countAlias: 'count',

    // 为了能够使用 `this` 获取局部状态,必须使用常规函数
    countPlusLocalState (state) {return state.count + this.localCount}
  })
}


computed: mapState([
  // 映射 this.count 为 store.state.count
  'count'
]

mapState 函数返回的是一个对象。computed: {localComputed () {/* ... */},
  // 使用对象展开运算符将此对象混入到外部对象中
  ...mapState({// ...})
}

需要从 store 中的 state 中派生出一些状态

computed: {doneTodosCount () {return this.$store.state.todos.filter(todo => todo.done).length
  }
}

getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

const store = new Vuex.Store({

  state: {
    todos: [{ id: 1, text: '...', done: true},
      {id: 2, text: '...', done: false}
    ]
  },
  
  getters: {
    doneTodos: state => {return state.todos.filter(todo => todo.done)
    }
  }
  
})

Getter 会暴露为 store.getters 对象

store.getters.doneTodos 

// -> [{id: 1, text: '...', done: true}]

Getter 也可以接受其他 getter 作为第二个参数:

getters: {
  // ...
  doneTodosCount: (state, getters) => {return getters.doneTodos.length}
}

store.getters.doneTodosCount // -> 

computed: {doneTodosCount () {return this.$store.getters.doneTodosCount}
}
getters: {
  // ...
  getTodoById: (state) => (id) => {return state.todos.find(todo => todo.id === id)
  }
}

store.getters.getTodoById(2) 
// -> {id: 2, text: '...', done: false}

mapGetters 辅助函数是将 store 中的 getter 映射到局部计算属性:

import {mapGetters} from 'vuex'

export default {
  // ...
  computed: {
  // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }
}
mapGetters({
  // 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
  doneCount: 'doneTodosCount'
})

Vuex 的 store 中的状态的唯一方法是提交 mutation

每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)

向 store.commit 传入额外的参数,即 mutation 的 载荷(payload):

// ...
mutations: {increment (state, n) {state.count += n}
}

store.commit('increment', 10)

在大多数情况下,载荷应该是一个对象

可以包含多个字段并且记录的 mutation

// ...
mutations: {increment (state, payload) {state.count += payload.amount}
}

store.commit('increment', {amount: 10})

store.commit({
  type: 'increment',
  amount: 10
}

mutations: {increment (state, payload) {state.count += payload.amount}
}

Action

简单的 action:

const store = new Vuex.Store({
  state: {count: 0},
  mutations: {increment (state) {state.count++}
  },
  actions: {increment (context) {context.commit('increment')
    }
  }
}

store.dispatch('increment')

store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise

actions: {actionA ({ commit}) {return new Promise((resolve, reject) => {setTimeout(() => {commit('someMutation')
        resolve()}, 1000)
    })
  }
}
store.dispatch('actionA').then(() => {// ...}

actions: {
  // ...
  actionB ({dispatch, commit}) {return dispatch('actionA').then(() => {commit('someOtherMutation')
    })
  }
}

// 假设 getData() 和 getOtherData() 返回的是 Promise

actions: {async actionA ({ commit}) {commit('gotData', await getData())
  },
  async actionB ({dispatch, commit}) {await dispatch('actionA') // 等待 actionA 完成
    commit('gotOtherData', await getOtherData())
  }
}

文件:

const moduleA = {state: { ...},
  mutations: {...},
  actions: {...},
  getters: {...}
}

const moduleB = {state: { ...},
  mutations: {...},
  actions: {...}
}

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

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态 
store.js 文件:import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {num: 1},
  mutations: {changeFunction (state, num) {state.num++}
  }
})

main.js 文件:import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

views/demo.vue 文件:<template>
  <div>
    <p>{{msg}}</p>
    <button @click="getNum">getNum</button>
  </div>
</template>

<script>
export default {data () {
    return {msg: '0'}
  },
  methods: {getNum () {this.msg = this.$store.state.num}
  }
}
</script>

想要获得 vuex 里的全局数据,可以把 vue 看做一个类

模块化:

const moduleA = {
  namespaced: true,
  state: {name: ''},
  getters: {},
  mutations: {},
  actions: {}}
export default moduleA;
const moduleB = {
  namespaced: true,
  state: {name: ''},
  getters: {},
  mutations: {},
  actions: {}}
export default moduleB;
import moduleA from './moduleA.js';
import moduleB from './moduleB.js';
const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})
export default store;
this.$store.state.a.name // -> moduleA 的状态 name
this.$store.state.b.name // -> moduleB 的状态 name
computed: {
    ...mapState('a', {name: state => state.name}),
    ...mapState('b', {name: state => state.name})
}

state 示例

const state = {
  name: 'weish',
  age: 22
};
 
export default state;
getters.js 示例

export const name = (state) => {return state.name;}
 
export const age = (state) => {return state.age}
 
export const other = (state) => {return `My name is ${state.name}, I am ${state.age}.`;
}

参考官方文档:https://vuex.vuejs.org/

关于目前文章内容即涉及前端,PHP 知识点,如果有兴趣即可关注,很荣幸,能被您发现,真是慧眼识英!也感谢您的关注,在未来的日子里,希望能够一直默默的支持我,我也会努力写出更多优秀的作品。我们一起成长,从零基础学编程,将 Web 前端领域、数据结构与算法、网络原理等通俗易懂的呈现给小伙伴。分享 Web 前端相关的技术文章、工具资源、精选课程、热点资讯。


若本号内容有做得不到位的地方(比如:涉及版权或其他问题),请及时联系我们进行整改即可,会在第一时间进行处理。


请点赞!因为你们的赞同 / 鼓励是我写作的最大动力!

欢迎关注达达的 CSDN!

这是一个有质量,有态度的博客

正文完
 0