首页 技术 正文
技术 2022年11月20日
0 收藏 726 点赞 3,582 浏览 7976 个字

Vuex基本概念

  • State
  • Getter
  • Mutation
  • Action
  • Module

简单的Store

import Vue from 'vue';
import Vuex from 'vuex';Vue.use(vuex);const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++;
}
}
});store.commit('increment');
console.log(store.state.count);// 1

常见流程

Vue Component –dispatch–> Action

Action –commit–> Mutations

Mutations –mutate–> State

State –render–> Vue Component

State

获取vuex中的状态方法

计算属性:computed中返回某个状态,要获取Vuex那个状态,要在computed中定义

由于在全局使用了Vue.use(Vuex),所有组件可以通过this.$store拿到Vuex的store

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

由于computed的属性是函数,那么在返回状态之前,还有更多操作的空间。

mapState辅助函数

import {mapState} from 'vuex'

mapState辅助函数接收一个对象或者一个字符串数组,返回计算属性:computed

//这个可以单独放在一个文件中,重复使用
const vuexComputed = mapState({
//使用函数一定要有返回值 //箭头函数写法,第一参数是state
count: state => state.count, //字符串形式 'count' 等同于 state => state.count
countAlias: 'count', //可以使用'this'获取局部状态,使用常规函数,'this'会绑定为 computed的组件实例
countPlusLocalState (state) {
return state.count + this.localCount;
}
});

然后将mapState生成的vuexComputed和Vue组件实例的computed合并

使用对象展开运算符...

{
//...某个组件 computed: {
localComputed () {},
//使用对象展开运算符将vuexComputed混入到外部对象中
...vuexComputed
}
}

如果状态都只是单纯的显示,可以传一个字符串数组mapState

const vuexComputed = mapState(['count']);

完整的demo:

//main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import Vuex from 'vuex'
import axios from 'axios'Vue.use(Vuex)const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})store.commit('increment')
console.log(store.state.count)Vue.config.productionTip = false
Vue.prototype.$http = axios/* eslint-disable no-new */
new Vue({
el: '#app',
store,
router,
components: { App },
template: '<App/>'
})

main.js要使用Vue.use(Vuex)以及将store添加到全局new Vue({store})

下面的所有子组件才可以拿到store

<template>
<div class="hello">
<div>{{count}}</div>
<div>{{countAlias}}</div>
<div>{{countPlusLocalState}}</div>
</div>
</template>
//Component HelloWorld
import {mapState} from 'vuex'const vuexComputed = mapState({
count: state => state.count,
countAlias: 'count',
countPlusLocalState (state) {
return state.count + this.localCount
}
})export default {
name: 'HelloWorld',
data () {
return {
localCount: 2
}
},
computed: {
...vuexComputed
}
}

Getter

Getter计算属性:computed功能一样,只不过,它是store的,也会缓存计算的值。

组件中拿到getter

Getter会暴露store.getters对象。

const store = new Vuex.Store({
state: {
count: 0,
arr: [1, 2, 3, 4, 5, 6]
},
mutations: {
increment (state) {
state.count++
}
},
getters: {
get6: state => {
return state.arr.filter(num => num === 6)
}
}
})
{
//...某个组件
computed: {
get6 () {
return this.$store.getters.get6
}
}
}

在定义getter时,有两个参数传入stategetters

getters: {
get6: state => state.arr.filter(num => num === 6),
getNum: (state, getters) => {
return getters.get6
}
}

定义getter方法

//要使用函数要封装2层函数以上,在组件中拿到getTodoById时,默认执行第一层
getters: {
getTodoById: state => id => state.todos.find(todo => todo.id === id)
}store.getters.getTodoById(2)

mapGetters

功能:将store中的getter映射到局部的计算属性computed

mapState类似,支持传入对象或者字符串数组,不过只能获取,不能重写,或者定义

//store
{
state: {
arr: [1, 2, 3, 4, 5, 6, 7, 8]
},
getters: {
get6: state => {
return state.arr.find(num => num === 6)
},
getNum: state => num => state.arr.find(n => n === num) || '错误num'
}
}
<template>
<div class='helloworld'>
<div>{{get6}}</div>
<div>{{getNum(4)}}</div>
</div>
</template>
const vuexGetter = mapGetters(['get6', 'getNum']);//如果想定义别名使用对象的方式
//const vuexGetter = mapGetters({getSix: 'get6', getNumber: 'getNum'})export default {
name: 'HelloWorld',
data () {
},
computed: {
...vuexGetter
}
}

Mutation

修改Vuexstore中的状态的唯一方式是commit mutation

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

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

Payload

mutations: {
increment (state, n) {
state.count += n
}
}
store.commit('increment', 10)

store.commit可以支持多参数模式,或者一个对象模式

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

其中一个对象模式redux很像

而且事件类型type也可以使用常量来替代

// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION';// store.js
import Vuex from 'vuex';
import { SOME_MUTATION } from './mutation-types';const store = new Vuex.Store({
state: { ... },
mutations: {
// 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名
[SOME_MUTATION] (state) {
// mutate state
}
}
})

组件中提交mutation

在组件中可以通过this.$store.commit('xxx')提交mutation

还有就是使用mapMutations辅助函数,不过这次不是映射到计算属性,而是methods

使用方式和mapGetters一模一样

import { mapMutations } from 'vuex';//对象的方式可以重新命名,字符串数组是直接引用
const vuexMutations = mapMutations(['increment']);export default { methods: {
...vuexMutations
}
}

Mutation 和 Reduce

Reduce的基本形式

(state, Action) => newState || state

转化为Mutation,那么

const Action = {
type: 'increment',
amount: 10
}const initState = {
count: 0
}export default (state = initState, Action) => {
switch(Action.type){
'increment':
return Object.assign({},state,{count: Action.amount + state.count})
default:
return state
}
}

redux中改变状态:

store.dispatch(Action) -> reduce(state, Action) -> newState -> render view

mutation中改变状态:

store.commit('increment', playload) -> mutations['increment'](state, playload) -> newState -> render view

Action

一般Action可以处理异步任务,而Mutation必须只能同步。

在异步流程中,先异步获得所需的数据,然后将返回的数据组合成Action

在生成Action之前,有个createAction函数

//Redux 思维的Action
const createAction = async (url) => {
const resData = await asyncGetData(url) return {
type: 'SOME_TYPE',
resData
};
};//Action 是对象
const Action = createAction('some url')store.commit(Action)

Vuex中的ActionRedux是有区别的

Vuex中的Action充当着createAction的功能

commit应当只在action中使用,在commit之前还有dispatch

Redux中,dispatch分发的直接是action

Vuex中,dispatch分发的是createAction或者mutation,之后再commit action

Action 不同于 Mutation

  • Action提交的是mutation,而不是直接变更状态
  • Action可以包含任意异步操作
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})

Action函数接受一个与store实例具有相同方法和属性的context对象

其中context不是store实例

分发Action

store.dispatch('increment')

组件中分发Action

组件中使用this.$store.dispatch('xxx')

或者使用mapActions辅助函数将actions映射到methods

组合Action

dispatch函数在结束后返回一个Promise

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

Module

可以将store分割成模块Module

每个模块拥有自己的State、Mutation、Action、Getter

然后将所有模块组合成一个,就形成了一个状态树。

//一般我们可以按页面或者功能模块来划分模块
//大型项目可以按一个大模块划分
//然后在大漠块中再按页面划分
//如果还要更细,页面也可以切割成多个模块//页面A的状态
const pageA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}//页面B的状态
const pageAB = {
state: { ... },
mutations: { ... },
actions: { ... }
}const store = new Vuex.Store({
modules: {
a: pageA,
b: pageAB
}
})store.state.a // -> pageA 的状态
store.state.b // -> pageAB 的状态

模块的局部状态

每个模块的state都是局部状态,模块中的gettermutation、传进来的state都是局部的

action可以通过context.state拿到局部的状态,context.rootState拿到全局的

不同于mutationgetter也可以拿到全局状态,getter的第三个参数rootState

命名空间

默认情况下,模块内部的action、mutation和getter是注册在全局命名空间的–多个模块对同一mutation或action作出响应

多个模块对同一mutation或action作出响应,类似一个事件拥有多个处理程序(观察者模式)

在模块中添加namespace: true可以避免添加到全局队列中

添加命名空间后的getter : (state, getters, rootState, rootGetters) => {}

添加命名空间后的action context : getters访问局部的 rootGetters访问全局的

如果添加了命名空间,但是还是想暴露某个actiongetter为全局,使用root:true

{
actions: {
someOtherAction ({dispatch}) {
dispatch('someAction')
}
},
modules: {
foo: {
namespaced: true, actions: {
someAction: {
root: true,
handler (namespacedContext, payload) { ... } // -> 'someAction'
}
}
}
}
}

mapStatemapGettersmapActionsmapMutations绑定带命名空间的模块。

computed: {
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions('some/nested/module', [
'foo',
'bar'
])
}

还可以使用createNamespacedHelpers来绑定命名空间值,类似bind(context)

import { createNamespacedHelpers } from 'vuex';const { mapState, mapActions } = createNamespacedHelpers('some/nested/module');export default {
computed: {
// 在 `some/nested/module` 中查找
...mapState({
a: state => state.a,
b: state => state.b
})
},
methods: {
// 在 `some/nested/module` 中查找
...mapActions([
'foo',
'bar'
])
}
}

模块动态注册

// 注册模块 `myModule`
store.registerModule('myModule', {
// ...
})
// 注册嵌套模块 `nested/myModule`
store.registerModule(['nested', 'myModule'], {
// ...
})//卸载'myModule',只能卸载动态装载的模块
store.unregisterModule('myModule')

应用

如果是小型应用,可以按页面来分模块

//pagea.js
export default {
namespace:true,
state: {},
getters: {},
mutations: {},
actions: {}
}//pageb.js
//pagec.js
//paged.js
//以上页面也是按pagea.js的方式

然后用一个文件引进所有模块,且全部暴露export

//modules.js
import pageA from './pagea.js'
import pageB from './pageb.js'
import pageC from './pagec.js'
import pageD from './paged.js'export default {
pageA,
pageB,
pageC,
pageD
}

最后在main.js引入

//main.js
import modules from './modules/modules'//将模块装进Store树中
const store = new Vuex.Store({
//全局
state: {},
getters: {},
mutations: {},
actions: {},
//模块
modules
})
//在组件中可以
this.$store.state.pageA
this.$store.state.pageB
this.$store.state.pageC
this.$store.state.pageD
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,078
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,553
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,402
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,177
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,814
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,898