封面

vue框架状态管理之vuex

作为一个全沾攻城狮,需要会的东西实在太多了。虽然思路都大同小异,但是对于不同的框架,架构和使用的api都有着不小的区别,还是需要花费点时间学习一下,今天要记录的是便是管理vue状态的框架vuex。

vuex是什么

vuex是一个状态管理框架,也可以叫做数据共享框架。它能够创建一个独立于组件之外的一个共享数据仓储,将需要的数据放在store当中,当需要用到数据的组件通过this.$store.state.xxx获取 。

不使用vuex的现状

父向子传值: v-bind,子组件通过props接收。

子向父传值: $emit()发射自定义事件, 父组件用v-on监听事件。

不相干组件传值,eventbus实现。 接收方用$on,传递方用$emit()

此种方式只能在小型项目中使用,当需要大量组件需要传值时,会通过其他不相干的组件层层传递,导致组件之间耦合严重,维护相当吃力。

使用vuex有什么好处

vuex创建的state是独立于组件的,能够解藕组件。

集中管理数据,易于维护。

共享数据,存储和获取都非常便捷。

state中的数据都是响应式的,引用state的组件能够实时同步UI

存储原则:一般来说将需要共享的数据放在state中,私有的数据放在组件的data中。但是也可以将所有数据都放在state中,这要看个人和项目组的的开发习惯。

vuex组成部分

解构注意事项: state和getter本质上是属性,所以解构的时候是放在computed中,actions和mutactions是方法,所以解构是要放在methods中。

state(公共数据源,需要共享的数据都放在这里面)

使用的时候: this.$store.state.count (this可以省略)

或者使用mapState解构为computed属性,使用哪种方法都可以

<template>
<div>
{{count}}
</div>
</template>

<script>
import { mapState } from 'vuex'
export default {

computed: {
...mapState([
'count'
])
}

}
</script>

mutations(同步的修改state,mutations中不能使用异步操作)

用setTimeoutt等异步操作会出错 ,异步操作需要放在action中

好处:在统一的地方对应,方便管理和维护

add (state) {
state.count++
},
addN (state, n) {
state.count += n
}

使用时

第一种

this.$store.commit('add')

如果想传递参数

this.$store.commit('addN',3)

第二种mapMutations (注意要放在methods中)

 import { mapMutations } from 'vuex'  
/// 省略其他内容
methods: { ...mapMutations([ 'add', 'addN' ]) }

actions(异步的修改state,它不能直接操作state,需要调用mucations中的方法来操作)

mutations: {
add (state) {
state.count++
},
addN (state, n) {
state.count += n
}
},
actions: {
addAsync (context) {
setTimeout(() => {
context.commit('add')
}, 1000)
},
addNAsync (context,n) {
setTimeout(() => {
context.commit('addN',n)
}, 1000)
}

},

使用时:方式一

写一个方法,通过$store.dispatch这个action,想要传参数和mucation中写法一样

methods: {
handleAsyncAdd () {
this.$store.dispatch('addAsync')
},
handleAsyncAddN () {
this.$store.dispatch('addNAsync',4)
}

}

第二种使用方法,解构出来直接使用(注意要放在methods中)

methods:{
...mapActions([
'addAsync',
'addNAsync'
]),
}

<div @click="addAsync">

getters(用于对store中的数据进行加工形成新的数据,但不会影响store中的数据)

store的数据变化之后,getter中的数据也会变化

getters: {
showNum (state) {
return `当前最新的数量 ${state.count}`
}
},

使用时

<div @click="addAsync">
{{$store.getters.showNum}}
</div>

第二种使用方法(注意要放在computed中)

computed: {
...mapGetters([
'showNum'
])
}

使用时

<div @click="addAsync">
{{showNum}}
</div>

modules(对store进行模块划分)

使用场景:当项目组中有多个人同时开发时,如果放在一个文件里面则会出现修改冲突,这里需要使用modules进行文件切分再组合。

目录结构:

image-20201028145155073

// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

import users from './users'
import todos from './todos'

Vue.use(Vuex)

export default new Vuex.Store({
modules: {
users,
todos
}
})
// /store/todos/index.js
import todoStates from './todoStates'
import todoActions from './todoActions'
import todoMutations from './todoMutations'
import todoGetters from './todoGetters'

export default {
namespaced: true,
state: todoStates,
mutations: todoMutations,
actions: todoActions,
getters: todoGetters
}
//  /store/users.js
import userStates from './userStates'
import userActions from './userActions'
import userMutations from './userMutations'
import userGetters from './userGetters'

export default {
namespaced: true,
state: userStates,
mutations: userMutations,
actions: userActions,
getters: userGetters
}

使用的时候,解构的时候写法有区别。commit的时候需要加上模块名

<template>
<div>
<button @click="addTodo">add</button>
<li v-for="todo in todoList" :key="todo.name">
{{todo.name}}
</li>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex'

export default {
computed: {
...mapState({
todoList: state => state.todos.todoList
})
},
methods: {
...mapMutations({
addTodo (commit) {
commit('todos/addTodo', 'test')
}
})
}
}
</script>

使用注解方式

只有使用ts的环境才能使用注解方式,通过调研有以下两种方案。至于怎么选择,看实际项目的情况下,有的时候不一定有发言权,leader定哪个就用哪个吧。

vuex-module-decorators 用法

yarn add vuex-module-decorators

import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators'

@Module
export default class Counter2 extends VuexModule {
count = 0

@Mutation
increment(delta: number) {
this.count += delta
}
@Mutation
decrement(delta: number) {
this.count -= delta
}

// action 'incr' commits mutation 'increment' when done with return value as payload
@Action({ commit: 'increment' })
incr() {
return 5
}
// action 'decr' commits mutation 'decrement' when done with return value as payload
@Action({ commit: 'decrement' })
decr() {
return 5
}
}

vuex-class用法

yarn add vuex-class

import Vue from 'vue'
import Component from 'vue-class-component'
import {
State,
Getter,
Action,
Mutation,
namespace
} from 'vuex-class'

const someModule = namespace('path/to/module')

@Component
export class MyComp extends Vue {
@State('foo') stateFoo
@State(state => state.bar) stateBar
@Getter('foo') getterFoo
@Action('foo') actionFoo
@Mutation('foo') mutationFoo
@someModule.Getter('foo') moduleGetterFoo

// If the argument is omitted, use the property name
// for each state/getter/action/mutation type
@State foo
@Getter bar
@Action baz
@Mutation qux

created () {
this.stateFoo // -> store.state.foo
this.stateBar // -> store.state.bar
this.getterFoo // -> store.getters.foo
this.actionFoo({ value: true }) // -> store.dispatch('foo', { value: true })
this.mutationFoo({ value: true }) // -> store.commit('foo', { value: true })
this.moduleGetterFoo // -> store.getters['path/to/module/foo']
}
}

参考文章:

Vue & TypeScript 初体验 - 使用Vuex (vuex-module-decorators)

文章目录
  1. 1. vuex是什么
  2. 2. 不使用vuex的现状
  3. 3. 使用vuex有什么好处
  4. 4. vuex组成部分
    1. 4.0.1. state(公共数据源,需要共享的数据都放在这里面)
    2. 4.0.2. mutations(同步的修改state,mutations中不能使用异步操作)
    3. 4.0.3. actions(异步的修改state,它不能直接操作state,需要调用mucations中的方法来操作)
    4. 4.0.4. getters(用于对store中的数据进行加工形成新的数据,但不会影响store中的数据)
    5. 4.0.5. modules(对store进行模块划分)
  • 5. 使用注解方式
    1. 5.0.1. vuex-module-decorators 用法
    2. 5.0.2. vuex-class用法


  • twitter分享


    如果想及时收到回复,可在 订阅中心Participating中勾选Email

    Fork me on GitHub