vuex文档(附加个人理解)

Vuex是什么?

Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel调试、状态快照导入导出等高级调试功能。

反正我是懵懵的,没太看懂他有什么用。 (~ ̄▽ ̄)~

什么是“状态管理模式”? 
让我们从一个简单的 Vue 计数应用开始:

    new Vue({
    // state
    data () {
         return {
           count: 0
        }
    },
    // view
     template: `<div>{{ count }}</div>`,
    // actions
    methods: {
    increment () {
       this.count++
     }   } }) 

这个状态自管理应用包含以下几个部分: 
state,驱动应用的数据源; view,以声明方式将state映射到视图; actions,响应在view上的用户输入导致的状态变化。

我的理解是 state状态就是数据源,通常用data,view是视图层不用说,通常用template,action就是方法进行一些数据操作,通常用methods。

当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:

-多个视图依赖于同一状态。 
-来自不同视图的行为需要变更同一状态。

应该是 很多视图层文件都是同一个数据来源,不同视图的操作需要改为同一个数据源。

对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。

因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者出发行为!

另外,通过定义和隔离状态管理中的各种概念并强制遵守一定的规则,我们的代码将会变得更结构化且易维护。

这就是 Vuex 背后的基本思想,借鉴了 Flux、Redux、和 The Elm Architecture。与其他模式不同的是,Vuex 
是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。

也就是遇到上述问题怎么办呢,Vuex将数据源打包了,然后要操作的时候,都从这个数据源来操作,不会有那种继承父组件,多层组件嵌套导致不利于维护的情况。

什么情况下我应该使用 Vuex?

虽然 Vuex 可以帮助我们管理共享状态,但也附带了更多的概念和框架。这需要对短期和长期效益进行权衡。

如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 
global event bus 
就足够您所需了。但是,如果您需要构建是一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。引用 
Redux 的作者 Dan Abramov 的话说就是:

Flux 架构就像眼镜:您自会知道什么时候需要它。

其实我真的觉得这段话说了等于没说。。。 ㄟ( ▔, ▔ )ㄏ

每一个 Vuex 应用的核心就是 store(仓库)。”store” 基本上就是一个容器,它包含着你的应用中大部分的状态(即state)。Vuex 和单纯的全局对象有以下两点不同:

1.Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store中的状态发生变化,那么相应的组件也会相应地得到高效更新。

2.你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交mutations。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

1大概也就是数据绑定,同步更新数据,2不是很懂,mutations是什么东西?

最简单的 Store

提示:我们将在后续的文档示例代码中使用 ES2015 语法。如果你还没能掌握 ES2015,你得抓紧了!

安装 Vuex 之后,让我们来创建一个 store。创建过程直截了当——仅需要提供一个初始 state 对象和一些 mutations:

// 如果在模块化构建系统中,请确保在开头调用了 Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})

现在,你可以通过 store.state 来获取状态对象,以及通过 store.commit 方法触发状态变更:

store.commit(‘increment‘)

console.log(store.state.count) // -> 1

再次强调,我们通过提交 mutation 的方式,而非直接改变

store.state.count,是因为我们想要更明确地追踪到状态的变化。这个简单的约定能够让你的意图更加明显,这样你在阅读代码的时候能更容易地解读应用内部的状态改变。此外,这样也让我们有机会去实现一些能记录每次状态改变,保存状态快照的调试工具。有了它,我们甚至可以实现如时间穿梭般的调试体验。

由于 store 中的状态是响应式的,在组件中调用 store 中的状态简单到仅需要在计算属性中返回即可。触发变化也仅仅是在组件的methods 中提交 mutations。

这是一个最基本的 Vuex 记数应用示例。

接下来,我们将会更深入地探讨一些核心概念。让我们先从 State 概念开始。

反正每次对数据对象进行操作的时候,都需要进行commit,好处就是他上面说的,但是现在不在项目中,肯定体会不到好处,就像redux作者说的“您自会知道什么时候需要它。”

state

单一状态树

Vuex 使用 单一状态树 —— 
是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个『唯一数据源(SSOT)』而存在。这也意味着,每个应用将仅仅包含一个 store 
实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。

单状态树和模块化并不冲突 —— 在后面的章节里我们会讨论如何将状态和状态变更事件分布到各个子模块中。

每个应用将仅仅包含一个 store

在 Vue 组件中获得 Vuex 状态

那么我们如何在 Vue 组件中展示状态呢?由于 Vuex 的状态存储是响应式的,从 store 
实例中读取状态最简单的方法就是在计算属性中返回某个状态:

// 创建一个 Counter 组件
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return store.state.count
    }
  }
}

每当 store.state.count 变化的时候, 都会重新求取计算属性,并且触发更新相关联的 DOM。

然而,这种模式导致组件依赖的全局状态单例。在模块化的构建系统中,在每个需要使用 state 
的组件中需要频繁地导入,并且在测试组件时需要模拟状态。

Vuex 通过 store 选项,提供了一种机制将状态从根组件『注入』到每一个子组件中(需调用 Vue.use(Vuex)):

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

通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store访问到。让我们更新下 Counter 的实现:

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

通过一种类似虚拟主机的机制,将store注入到每个子组件,然后子组件就能操作store了,还是有点像继承。

mapState 辅助函数

当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 
辅助函数帮助我们生成计算属性

这个我看的不是很懂,只知道他是辅助计算属性的。

mapState函数返回的是一个对象。我们如何将它与局部计算属性混合使用呢?通常,我们需要使用一个工具函数将多个对象合并为一个,以使我们可以将最终对象传给 computed 属性。但是自从有了对象展开运算符(现处于 ECMASCript 提案 stage-3 阶段),我们可以极大地简化写法。

上面的没懂,那这个等等再说。

Getters

有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数:

computed: {
  doneTodosCount () {
    return this.$store.state.todos.filter(todo => todo.done).length
  }
}

如果有多个组件需要用到此属性,我们要么复制这个函数,或者抽取到一个共享函数然后在多处导入它 —— 无论哪种方式都不是很理想。

Vuex 允许我们在 store 中定义『getters』(可以认为是 store 的计算属性)。Getters 接受 state 作为其第一个参数:

const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: ‘...‘, done: true },
      { id: 2, text: ‘...‘, done: false }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
  }
})

Getters 会暴露为 store.getters 对象:

store.getters.doneTodos // -> [{ id: 1, text: ‘...‘, done: true }]

Getters 也可以接受其他 getters 作为第二个参数:

getters: {
  // ...
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }
}
store.getters.doneTodosCount // -> 1

我们可以很容易地在任何组件中使用它:

computed: {
  doneTodosCount () {
    return this.$store.getters.doneTodosCount
  }
}

getters可以认为是 store 的计算属性,也就是多次调用,所以将其封装成getters,方便调用。

mapGetters 辅助函数

mapGetters 辅助函数仅仅是将 store 中的 getters 映射到局部计算属性:

import { mapGetters } from ‘vuex‘

export default {
  // ...
  computed: {
  // 使用对象展开运算符将 getters 混入 computed 对象中
    ...mapGetters([
      ‘doneTodosCount‘,
      ‘anotherGetter‘,
      // ...
    ])
  }
}

如果你想将一个 getter 属性另取一个名字,使用对象形式:

mapGetters({
  // 映射 this.doneCount 为 store.getters.doneTodosCount
  doneCount: ‘doneTodosCount‘
})

和上面的state一样,没太明白。不着急。

Mutations

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutations 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

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

你不能直接调用一个 mutation handler。这个选项更像是事件注册:“当触发一个类型为 increment 的 mutation 时,调用此函数。”要唤醒一个 mutation handler,你需要以相应的 type 调用 store.commit 方法:

store.commit(‘increment‘)

我到现在还是没有明白 mutations是干什么的,具体有什么用。只知道要操作state就是要commit mutations。

提交载荷(Payload)

你可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload):

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

在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读:

// ...
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
store.commit(‘increment‘, {
  amount: 10
})

不知道载荷用的多不多,感觉还挺多的,荷载就是 commit额外的参数。

对象风格的提交方式

提交 mutation 的另一种方式是直接使用包含 type 属性的对象:

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

当使用对象风格的提交方式,整个对象都作为载荷传给 mutation 函数,因此 handler 保持不变:

mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}

感觉这种风格更适用于vue,更像vue的写法

Mutations 需遵守 Vue 的响应规则

既然 Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项:

最好提前在你的 store 中初始化好所有所需属性。

当需要在对象上添加新属性时,你应该使用 Vue.set(obj, ‘newProp‘, 123), 或者 -

以新对象替换老对象。例如,利用 stage-3 的对象展开运算符我们可以这样写:

state.obj = { ...state.obj, newProp: 123 }

规则很重要,我愣是挤出了这几个没用的字。 Σ( ° △ °|||)︴

使用常量替代 Mutation 事件类型

使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式。这样可以使 linter 之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然:

// 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 必须是同步函数

一条重要的原则就是要记住 mutation 必须是同步函数。为什么?请参考下面的例子:

mutations: {
  someMutation (state) {
    api.callAsyncMethod(() => {
      state.count++
    })
  }
}

现在想象,我们正在 debug 一个 app 并且观察 devtool 中的 mutation 日志。每一条 mutation 被记录,devtools 都需要捕捉到前一状态和后一状态的快照。然而,在上面的例子中 mutation 中的异步函数中的回调让这不可能完成:因为当 mutation 触发的时候,回调函数还没有被调用,devtools 不知道什么时候回调函数实际上被调用 —— 实质上任何在回调函数中进行的的状态的改变都是不可追踪的。

这个如果不是同步函数的话,就显示不了回调函数的状态日志了,可以这样理解吗?

在组件中提交 Mutations

你可以在组件中使用 this.$store.commit(‘xxx‘) 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。

import { mapMutations } from ‘vuex‘

export default {
  // ...
  methods: {
    ...mapMutations([
      ‘increment‘ // 映射 this.increment() 为 this.$store.commit(‘increment‘)
    ]),
    ...mapMutations({
      add: ‘increment‘ // 映射 this.add() 为 this.$store.commit(‘increment‘)
    })
  }
}

这个倒是能看懂

下一步:Actions

在 mutation 中混合异步调用会导致你的程序很难调试。例如,当你能调用了两个包含异步回调的 mutation 来改变状态,你怎么知道什么时候回调和哪个先回调呢?这就是为什么我们要区分这两个概念。在 Vuex 中,mutation 都是同步事务:

store.commit(‘increment‘)
// 任何由 "increment" 导致的状态变更都应该在此刻完成。

为了处理异步操作,让我们来看一看 Actions。

时间: 2024-09-28 03:58:30

vuex文档(附加个人理解)的相关文章

从文档流角度理解浏览器页面渲染引擎对元素定位的解析

文档流:将窗体自上而下分成一行一行,并在每行中按从左至右的挨次排放元素,即为文档流. 我们在排列元素时,遵循"流式结构",即元素遵循从上向下,从左向右堆叠的规则,所以我们在排列元素时如果每行从左往右的元素的总宽度大于窗口的宽度时,就会默认换行. 有三种状况将使得元素离开文档流而存在,分别是浮动.绝对定位.固定定位. 浮动时,离开文档流后的元素,不占用文档流的空间,不会被文档流中的元素发现,离开文档流元素后面的还在文档流上元素会自动上来填补位置接上文档流.此时,离开文档流的元素如同浮在文

关于MFC视图文档框架的理解-1

一.单个文档和多个文档的区别: MFC分为对话框程序,单文档程序和多文档程序. 单个文档程序:一个主框架内仅允许打开一个视图,若要打开另一个,则当前的文档必须得关闭.单文档程序可以打开不同格式的文档. 对于单文档程序,主框架(CFrameWnd).视图(CView).文档(CDocument)被文档模板CSingleDocTemplate粘合在一起. 多个文档程序:一个主框架内可以打开多个视图. 对于多文档程序,主框架(CMDIFrameWnd)是单独存在的,子框架(CMDIChildWnd).

谈谈对文档碎片的理解

js操作DOM时发生了什么? js每次操作DOM都出发了回流,这非常的消耗性能. 什么是文档碎片容器? document.createDocumentFrgement()----用于暂时存放创建的DOM元素. 文档碎片容器有什么用? 将需要添加到body中的元素先添加到碎片容器中,再把碎片容器插入到对应的位置,这样可以减少DOM操作,提高性能. 原文地址:https://www.cnblogs.com/wuqilang/p/11253627.html

Vuex 文档解读

Vuex 管理状态 state  单一状态树,意思是一个对象包含了全部应用层级状态,Store将作为唯一数据源. 每个应用,仅仅有且只有一个 store 实例! mapState 当一个组件组件组件需要多个状态值时,可以调用 mapState函数赋值给 computed 返回是对象. // mapState 基本用法,3种: 箭头函数, 字符串, 函数. computed:mapState({       //1,箭头函数 countFromStore:state=>state.count  

css中绝对定位和相对定位,文档流的理解

相关链接: http://blog.csdn.net/libertea/article/details/11662661 今天在这里看到了关于一个定位的博客,感觉讲的挺好的,在这里分享一下链接.

vuex最简单、最详细的入门文档

vuex最简单.最详细的入门文档 如果你在使用 vue.js , 那么我想你可能会对 vue 组件之间的通信感到崩溃 . 我在使用基于 vue.js 2.0 的UI框架 ElementUI 开发网站的时候 , 就遇到了这种问题 : 一个页面有很多表单 , 我试图将表单写成一个单文件组件 , 但是表单 ( 子组件 ) 里的数据和页面 ( 父组件 ) 按钮交互的时候 , 它们之间的通讯很麻烦 : <!--父组件中引入子组件--> <template> <div> <a

软件工程文档总结

吐槽一下 写文档之前,纠结了好长时间,不知道怎么写.文档完成了之后做总结,感觉又来了. 我在想,是不是别人在第一次写这个东西的时候也这么纠结. 搜集了好多文档的模板来看,找找感觉吧. 在都编辑完了之后发现这些文档也挺有规律性的,从一个软件开发之前,到开发完了之后都是需要有文档做辅助的,尤其是在编写“用户手册”的时候,也是在这篇文档上感触非常大,--为人民服务! 想起了之前忘了在哪里听到或看到的一句话,文档的质量.厚度.在很大程度上决定了这个软件的优秀与否.可能这是第一次写这个让人有点头疼的东西,

从文档流认识html

写html,css的同学应该需要清楚什么是文档流.文档流:将窗体自上而下分成一行一行,并在每行中按从左至右的挨次排放元素,即为文档流. 每个非浮动块级元素都独有一行, 浮动元素则按规则浮在行的一端. 若当时行容不下, 则另起新行再浮动.内联元素也不会独有一行. 一切元素(包括块级,内联和列表元素)均可生成子行, 用于摆放子元素.有三种状况将使得元素离开文档流而存在,分别是浮动.绝对定位.固定定位.然则在IE中浮动元素也存在于文档流中. 浮动元素不占任何正常文档流空间,而浮动元素的定位照样基于正常

文档总结(一)——文档的概述

写完文档后,本来想写一篇具体的文档的总结的,后来看大家都写的具体文档总结,于是我就想:我还是写一些跟大家不一样的东西吧. 所以,我就说说我对各个文档的宏观理解吧. 老规矩,先来一张图: 这是我们的文档,也可以说这是软件的前半生.它包括了我们的软件的从计划--设计--实现--测试的过程,至于之后的维护,估计是没有算在软件开发的文档里面,不过可以肯定的是绝对会有文档的. 文档是一种交流的方式,也是一种工作的证据,往好了说,文档便于团队去开发软件:往坏了说,软件就是一种证据,人家需求上写了,你的软件上