Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

使用 vuex 接管 vue 项目数据状态 #17

Open
sweeetcc opened this issue Feb 28, 2017 · 0 comments
Open

使用 vuex 接管 vue 项目数据状态 #17

sweeetcc opened this issue Feb 28, 2017 · 0 comments
Assignees

Comments

@sweeetcc
Copy link
Owner

sweeetcc commented Feb 28, 2017

eaae066a-4ab9-4431-91fe-2eff8a5cde35

vuex 解决的问题

类似于 redux,但是 vuex 更专注于 vue。它是专门为 vue 开发的一个“状态管理模式”。主要作用就是为了集中管理组件状态和数据,并使用规则来保证状态以一种“可预测”的方式发生变化。

vuex 背后的基本思想就是讲数据状态抽离出来,在全局以一个统一的 store 去管理,从而构成一个 “状态树”。不仅可以在任何地方取得相应的数据,还能够触发状态的更新。

vuex 和单纯的全局对象的不同在于

  1. vuex 的状态存储是响应式的,意思是如果组件状态是 store 状态的一部分,那么如果 store 上的状态更新,组件的状态也会得到相应的更新。
  2. 为了更方便的追踪整个状态树的变化,如果我们需要修改状态,不能够直接操作 store 进行状态修改,修改状态的唯一途径就是 commit mutations。

核心概念

Store

全局唯一的状态树。

注意: 并非需要把所有组件状态都放入状态树,对于有些严格属于某个组件的状态,可以在组件内维护状态,这些需要在开发过程中去权衡。

Getters

从 store 上获取某些数据的快捷方式,尤其是当要获取的数据需要满足一定条件的时候,我们需要添加各种条件和过滤等,等到我们想要的部分。如果这些数据过滤的逻辑写到每一个用到这些数据的地方,那么就会显得冗余。

所以,使用 getter 配合 mapGetters 我们能够更规范地获得数据。

Mutations

更改 vuex 的 store 上的数据的唯一办法就是提交 mutation。每一个 mutation 都有一个对应的 type 和回调函数。

几种提交方式:

  • 只提交 type:
store.commit(‘increment’)
  • 提交 type 和 payload:
store.commit('increment', 1)
  • 对象风格的提交方式:
store.commit({
	type: 'increment',
	amount: 1,
})

注意: mutations 需要遵守 vue 的响应式规则。

例如:

  1. 最好提前在你的 store 中初始化好所有所需属性。
  2. 需要在对象上添加新属性的时候,最好使用 set,Vue.set(obj, 'newProp', 123),或者,state.obj = { ...state.obj, newProp: 123 }。

注意: mutation 中必须是同步函数,否则应用的状态变得不可追踪。

在组件中,我们可以使用 mapMutations 方法。

Actions

action 类似于 mutation,不同的是 action 是提交 mutation,不直接更改状态;action 可以包含任意的异步操作。

action 函数接收一个与 store 实例具有相同方法的 context 对象,因此可以调用 context.commit 来提交 mutation,或者通过 context.getters context.state 来获取 getters 和 state。

分发 action:

为什么我们不直接分发 mutation?因为 mutation 中只能有同步操作,所以我们需要 dispatch action。在组件中,我们可以使用 mapActions。

Modules

为了防止单一文件过大,我们可以把整个 store 拆分成多个 modules,每个模块拥有自己的 state、getters、mutations、actions,类似于:

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 的状态

模块的局部状态:

  • 对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态。
const moduleA = {
  state: { count: 0 },
  mutations: {
    increment (state) {
      // state 模块的局部状态
      state.count++
    }
  },

  getters: {
    doubleCount (state) {
      return state.count * 2
    }
  }
}
  • 对于模块内部的 action,context.state 是局部状态,根节点的状态是 context.rootState。
const moduleA = {
  // ...
  actions: {
    incrementIfOddOnRootSum ({ state, commit, rootState }) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
  }
}
  • 对于模块内部的 getter,根节点状态会作为第三个参数。
const moduleA = {
  // ...
  getters: {
    sumWithRootCount (state, getters, rootState) {
      return state.count + rootState.count
    }
  }
}

模块的动态注册:

store.registerModule('myModule', {
  // ...
})

模块的状态将是 store.state.myModule。

vuex 在项目中的应用

项目结构规划:

29fdccca-a9f4-4c6d-8784-95014096b303

按照官方推荐的目录结构,先大体规划一下项目数据的整体结构:

store 目录下的 actions.js getters.js mutations.js 是全局的 action getters 和 mutations; mutation-types 会存放所有的 mutations 的类型常量,包括根 mutation 的以及 modules 下面的;然后就是我们的各个模块,存放在 modules 下,每个模块维护自己的 actions getters 和 mutations。

918f78f6-bf4c-4a34-81cf-ad8de6338289

当然这是针对比较大型的项目而言的,另外有几个需要注意的点:

  1. 应用层级的状态应该集中到单个 store 对象中。
  2. 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
  3. 异步逻辑都应该封装到 action 里面。

一个简单的例子:

可以用一个简单的例子来熟悉一下 vuex 的整体流程:

首先,需要声明我们的 state 初始结构:

这里我设置的是根 state

d6b79f26-9e8e-485d-8b9d-406d8e626944

然后,我们可以根据需要设置相应的 action:

比如,我想要在全局有一个 sayHello 的 action,可以这样定义:

90ee5814-a5e6-496e-b61b-3709254ff2c9

然后,我的 action 接收一个 name 属性,除了打印,还会触发 mutation:

所以,我们需要有一个 mutation 来触发 state 的变化:

288d1ec9-e59d-4d8e-8fab-fa0226955359

最后,需要在组件里面分发 action:

6c0319ec-06c8-45e5-828a-efde4253b160

结果就是我们的 state 会对应地更新:

cfd4ec79-0408-4bf4-b925-0055f852c03b

@sweeetcc sweeetcc self-assigned this Feb 28, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant