Vue(四 Vuex)

状态管理模式,依赖Promise
单项数据流


image.png

多组件共享状态时,单项数据流会被破坏 ===》抽取组件的共享状态。以一个全局单例模式管理
在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!


image.png

1、store 仓库
包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:
1.1、Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

1.2、你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
2、state
vue使用单一状态树,每个应用将仅仅包含一个 store 实例
Vuex 通过 store 选项,提供了一种机制将状态从根组件“注入”到每一个子组件中(需调用 Vue.use(Vuex))

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

mapState 辅助函数
对象展开运算符
3、getter
可以理解成store的计算属性
4、mutation
改变store中状态的唯一途径就是提交mutation
必须是同步函数
可以在mutation中提交多个参数,第二个参数叫载荷payload

// ...
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
//...
store.commit('increment', {
  amount: 10
})
//对象风格
store.commit({
  type: 'increment',
  amount: 10
})

可以 使用常量代替mutation提交类型

 mutations: {
    // 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名
    [SOME_MUTATION] (state) {
      // mutate state
    }
  }

5、action
类似于mutation,区别:提交的是mutation;异步

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
//接受一个与 store 实例具有相同方法和属性的 context 对象,所以可以commit、getter等
    increment (context) {
      context.commit('increment')
    }
  }
})

分发store.dispatch?????
6、module

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

如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。
7、项目结构


image.png

8、插件
8.1、就是一个函数,接受store作为唯一的参数

const myPlugin = store => {
  // 当 store 初始化后调用
  store.subscribe((mutation, state) => {
    // 每次 mutation 之后调用
    // mutation 的格式为 { type, payload }
  })
}
// ...
const store = new Vuex.Store({
  // ...
  plugins: [myPlugin]
})

注意插件内也不能直接修改store,只能通过mutation来修改,
8.2、有时候插件需要获得状态的“快照”,比较改变的前后状态。想要实现这项功能,你需要对状态对象进行深拷贝

const myPluginWithSnapshot = store => {
  let prevState = _.cloneDeep(store.state)
  store.subscribe((mutation, state) => {
    let nextState = _.cloneDeep(state)

    // 比较 prevState 和 nextState...

    // 保存状态,用于下一次 mutation
    prevState = nextState
  })
}

生成状态快照的插件应该只在开发环境中使用,这一点个可以通过webpack来控制

const store = new Vuex.Store({
  // ...
  plugins: process.env.NODE_ENV !== 'production'
    ? [myPluginWithSnapshot]
    : []
})

8.3、logger插件,日志插件用来一般的调试,会生成状态快照,仅在开发环境使用

import createLogger from 'vuex/dist/logger'

const store = new Vuex.Store({
  plugins: [createLogger()]
})
//...
//几个配置项
const logger = createLogger({
  collapsed: false, // 自动展开记录的 mutation
  filter (mutation, stateBefore, stateAfter) {
    // 若 mutation 需要被记录,就让它返回 true 即可
    // 顺便,`mutation` 是个 { type, payload } 对象
    return mutation.type !== "aBlacklistedMutation"
  },
  transformer (state) {
    // 在开始记录之前转换状态
    // 例如,只返回指定的子树
    return state.subTree
  },
  mutationTransformer (mutation) {
    // mutation 按照 { type, payload } 格式记录
    // 我们可以按任意方式格式化
    return mutation.type
  },
  logger: console, // 自定义 console 实现,默认为 `console`
})

9、严格模式

const store = new Vuex.Store({
  // ...
// 不要在发布环境中开启严格模式,在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。有可能造成性能损失
  strict: process.env.NODE_ENV !== 'production'
})

10、表单处理
对于希望对vuex中store里数据进行双向绑定时
10.1、vuex的思路

<input :value="message" @input="updateMessage">
//...
computed: {
  ...mapState({
    message: state => state.obj.message
  })
},
methods: {
  updateMessage (e) {
    this.$store.commit('updateMessage', e.target.value)
  }
}
//...
mutations: {
  updateMessage (state, message) {
    state.obj.message = message
  }
}

10.2、使用带有 setter 的双向绑定计算属性

<input v-model="message">
//...
computed: {
  message: {
    get () {
      return this.$store.state.obj.message
    },
    set (value) {
      this.$store.commit('updateMessage', value)
    }
  }
}

11、测试
检测state值是否达到预期,那么我们主要是针对 Vuex 中的 mutation 和 action 进行单元测试,
11.1、motation
比较好测,就是一群一栏参数的函数 ,调用看看是不是符合预期就好
11.2、action
这个链接很棒:https://zhuanlan.zhihu.com/p/75513490
Action 应对起来略微棘手,因为它们可能需要调用外部的 API。当测试 action 的时候,我们需要增加一个 mocking 服务层——例如,我们可以把 API 调用抽象成服务,然后在测试文件中用 mock 服务回应 API 调用。为了便于解决 mock 依赖,可以用 webpack 和 inject-loader 打包测试文件。

image.png

image.png

12、热加载
对于 mutation 和模块,你需要使用 store.hotUpdate() 方法

image.png

image.png

https://juejin.im/post/5dba91e4518825647e4ef18b

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • vuex官方文档 一、vuex是什么 官方解释是:Vuex是通过全局注入store对象,来实现组件间的状态共享,是...
    好一只帅卤蛋阅读 330评论 0 1
  • 目录 1 引入 vuex 2 state 访问状态对象 3 mutations(同步) 模板获取方法 4 gett...
    林ze宏阅读 372评论 0 0
  • Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应...
    白水螺丝阅读 4,691评论 7 61
  • State 单一状态树 Vuex使用单一状态树——用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据...
    oWSQo阅读 1,101评论 0 0
  • 由于Vuex的官方文档在各个模块之间缺乏一些过渡,另外新概念很多,使得初读时总有些云里雾里的感觉。于是本文在官方文...
    一郭鲜阅读 359评论 0 1