浅谈 vuex

4,153 阅读4分钟
原文链接: github.com

上手Vue三个月,谈谈自己对Vuex的理解.(结合文档与实际项目)

Flux基本了解

概念

Flux是Facebook用于构建客户端Web应用程序提出的应用程序架构。它在React的视图组件中使用单向数据流。它更多的是一种模式,而不是一个正式的框架,您可以立即开始使用Flux,而不需要大量的新代码。

Flux应用有三个主要的概念: Dispatcher , Stores , Views(React 组件) .不要把这三个概念与传统的MVC(Model-View-Controller)相混淆.Flux避开MVC,有利于单向数据流。

Structure and Data Flow

Flux中的单项数据流

这里写图片描述

单向数据流是Flux模式的核心,Dispatcher , Stores , Views是具有不同输入和输出的独立节点。Action是包含新数据和识别类型属性的简单对象.

View: 视图层
Action(动作):视图层发出的消息(比如mouseClick)
Dispatcher(派发器):用来接收Actions、执行回调函数
Store(数据层):用来存放应用的状态,一旦发生变动,就提醒Views要更新页面

所以上图可以理解为:

Action触发Dispatcher中的回调函数,导致Store中的状态发生变化,最终影响View视图重新渲染.

另外一种模式: 见下图

视图View在与用户的交互过程中产生一个新的Action. Action被Dispatcher接收.触发Dispatcher中的回调函数执行,改变了Store中状态,Store状态更新,导致View层重新渲染.

这里写图片描述

Flux架构所有数据都是单项流动的.

这里只是为了更好理解Vuex,了解下基本的概念.
具体学习Flux

Vuex

以在Vuex中存储用户登陆后信息模块为例.

目录结构

 |-- store      # Vuex的根目录
	 |-- modules  #可以理解为该文件夹下每个js模块就是一个store 
		 |-- user.js  #demo: 用户登陆后的信息模块
	 |-- index.js  # 对外导出store
	 |-- mutation-types.js	#抽离出来的存放各种 mutation 事件类型的模块 

先上代码:

// index.js

import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
Vue.use(Vuex)
const debug = process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'production-runtime'
export default new Vuex.Store({
  modules: {
    user
  },
  strict: debug,
  plugins: debug ? [createLogger()] : []
})
// mutation-types.js

// User
export const SET_USER_INFO = 'SET_USER_INFO'
// user.js

import * as types from '../mutation-types'

// initial state
const state = {
  userInfo: {}
}

// getters
const getters = {
  getUserInfo: state => state.userInfo
}

// actions
const actions = {
  setUserInfo ({commit}, user) {
    commit(types.SET_USER_INFO, user)
  }
}

// mutations
const mutations = {
  [types.SET_USER_INFO] (state, userInfo) {
    state.userInfo = userInfo
  }
}

export default {
  state,
  getters,
  actions,
  mutations
}

// main.js  这里只引入部分代码

import store from './store'
const app = new Vue({
  ...
  store
}).$mount('#app')
// 只涉及部分代码	
// 与后端API的HTTP交互
// 当前demo场景就是用户登陆了,一个封装的login方法
// getApiJson: 封装获取数据的方法

 login (creds) {
    return getApiJson(LOGIN_API, creds)
      .then((res) => {
        if (res) {
          // user: 存储用户信息的对象
          let user = {
            loginName: res.user.loginName,
            avatarId: res.user.avatarId,
            employeeId: res.user.typeInstanceId,
            userId: res.id,
            name: res.user.name,
            token: res.token
          }
          // 通过store去分发setUserInfo(Action)+载荷user
          store.dispatch('setUserInfo', user)
          this.user.authenticated = true
          // 存储token与用户信息在sessionStorage
          sessionStorage.token = res.token
          sessionStorage.user = JSON.stringify(user)
        }
      })
  },

可能对于没接触过Vuex的看完这些代码有点小蒙,现在结合Vuex的概念与思想.

什么是Vuex?

Vuex是为Vue定制的一种状态管理模式,其核心思想借鉴了Flux、Redux、和 The Elm Architecture.

或者你也可以简单理解为Vuex,它是一个全局的(意味中对外都可以访问),单例模式的管理状态.Vue应用中任何组件都可以获取Vuex中的状态(数据)以及去触发Vuex的行为.

为什么需要Vuex?

这里写图片描述

相信使用Vue或者其他单页应用框架的大多数碰到这种情况.

如果我们通过props和事件在爷/父/孙进行通信,在多层组件嵌套的情况下,且不说行不行的通,代码过于臃肿,耦合过深,不利于维护和扩展.

这个时候就需要Vuex了,把需要A中的state存储起来,大家需要的直接从Vuex获取.并且Vuex是响应式的,动态更新.

当然也不是说什么状态都怼到Vuex,视具体业务情况.能够通过props/事件进行通信的,或者$refs(官网不建议过多使用)获取state的就不需要用Vuex了.

Vuex的核心概念

单项数据流

Vue是基于数据驱动.

这里写图片描述

理解

View : 视图(Vue组件)
State:状态(一般是一个对象,存储我们需要的数据信息)
Actions: 通过提交mutation,来改变State

用户与视图交互,触发Actions,执行Actions的回调,提交mutation,导致State发生改变,State重新渲染视图.

State

  • 单一状态树

我理解其实就是说State就是一个对象,包含你需要的应用状态(数据). 当然你要先对其进行一个初始化.

  • 为什么我们可以在每个组件获取Vuex

Vuex 通过 store 选项,从根组件『注入』到每一个子组件中(需调用 Vue.use(Vuex)).其实就是在new Vue()传入store,前面代码已经有就不重复贴了.

Getters

我们可以理解Getters为Store的计算属性,通过Getters可以对Store中State做处理.Getters 接受 state 作为其第一个参数,也可以接受其他 getters 作为第二个参数.

  • 在子组件去获取Vuex的状态

在计算属性中通过mapGetters辅助函数.将 store 中的 getters 映射到局部计算属性

 computed: {
    ...mapGetters([
      'getUserInfo'
    ])
  },

Mutations

几个重要点:

  • 更改 Vuex 的 store 中的State的唯一方法是提交(commit) mutation
  • 每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler),在回调函数中处理state.接受 state 作为第一个参数.
  • 不能直接调用一个 mutation handler,只可以通过commit(type)去触发一个 mutation handler.
  • commit()可以接受除state外的额外的参数,该参数称为mutation的载荷.载荷一般是包含多个字段(key)的对象.
  • 使用常量替代 Mutation 事件类型.最好就是把这些常量放在单独的文件中,统一管理,如我demo中的mutation-types.js.

Actions

  • Action 可以包含任意异步操作
  • Action里面实际执行的是提交mutation
  • 通过store.dispatch()分发Actions.
  • Actions 同样支持载荷方式和对象方式进行分发

Modules

Vuex 允许把store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter .这样更加方便管理,细粒度化.

对于模块内部的 mutation 和 getter,接收的第一个参数state是模块的局部状态对象。

更加详细的具体见官网文档:Vuex

最后理解这张图收官:

这里写图片描述

1. State渲染Vue组件(视图)
2. Vue组件(视图)与用户交互过程中分发(dispatch)Actions
3. Actions执行相应的回调,commit(type)
4. 触发Mutations的事件,更改Store中的State.
5. State发生变化,重新刷新视图Vue组件
6. Actions在与后台API进行HTTP交互时候触发.
7. Devtools: 一个Vue 的官方调试工具

有些点还没有领会,后面再改.