Vuex学习入门

艺术之所以存在,
    就是为了使人恢复对生活的感觉,
    为了使人感受事物,
    使石头显出石头的质感。

                --什克洛夫斯基
复制代码

什么是Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。

什么情况下需要用Vuex

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

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

总结以下,主要是以下两点:

  1. 方便所有组件共享信息,方便不同组件共享信息。
  2. 某个组件需要修改状态和需求。

组件之间传值方式

主流的几种Vue的组件间传递信息的方式,无非有以下几种:

  1. 通过 $emitprops 在父子组件中进行数据传递

  2. eventbus (全局事件)在中进行传递

  3. 利用localstorage、sessionstorage等存储手段来进行传递

毫无疑问,这些个方式都能完成我们所要的需求,但是在某种程度上面或多或少都有一些问题。例如:

  1. 利用 $emitprops 在兄弟关系嵌套比较深的情况之下,代码书写量将会大大的增加

  2. 全局事件在使用的时候可能被被多次触发、销毁时机掌握等等一系列的问题,同时作为全局事件所有页面都能监听、掌控事件可能会存在安全性问题等等...

  3. ...

针对以上三种传值方式存在各自的缺点,下面着重介绍以下主角Vuex的简单入门。

Vuex核心概念

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

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

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

上面就将vuex的四个核心选项:state mutations getters actions说了出来,下面我们通过实例来了解这几个概念。

简单入门

  • 第一步

新建一个.js 文件,名字位置任意,按照惯例,建议在/src/store,我们就在该文件里编辑代码。

文件位置 /src/store/index.js

// 引入vue 和 vuex
import Vue from 'vue'
import Vuex from 'vuex'

// 这里需要use一下,固定写法,记住即可
Vue.use(Vuex)

// 直接导出 一个 Store 的实例
export default new Vuex.Store({
 // 类似 vue 的 data
  state: {
    name: 'oldName'
  },
 // 类似 vue 里的 mothods(同步方法)
  mutations: {
    updateName (state) {
      state.name = 'newName'
    }
  }
})
复制代码

这一步其实就是新建一个store,但是我们还没在项目中使用。

  • 第二步

在入口文件引入上述文件, 并稍微改一下传给 new Vue()的参数,新增的行后面有备注。

文件位置 /src/main.js

import Vue from 'vue'
import App from './App.vue'
import store from './store'  //新增

Vue.config.productionTip = false

new Vue({
  router,
  store,  //新增
  render: h => h(App)
}).$mount('#app')

复制代码

以上2步,如果我们使用vue-cli脚手架创建初始化项目的时候,选择了Vuex,以上两步都是默认帮我们处理好了的,使用起来很方便。

  • 第三步

以上2步,其实已经完成了vuex的基本配置,接下来就是使用了。

文件位置 /src/App.vue

<template>
  <div>
    {{getName}}
    <button @click="changeName" value="更名">更名</button>
  </div>
</template>

<script>
export default {
  computed:{
    getName(){
        return this.$store.state.name
    }
  },
  methods:{
    changeName () {
        this.$store.commit('updateName')
    }
  }
}
</script>
复制代码

这里就是一个很普通的vue文件了,有区别的地方是这里我们需要用computed属性去获取 store 里的 "data"。

还有就是我们要改变数据的话,不再用 this.xxx = xxx 改成 this.$store.commit('updateName')

四大核心

State

首先是state,如何来获取state的值呢?一般是将这个值放置在computed里面,这样的话一旦数据发生改变的时候,就反馈到页面上面去。

computed:{
    getName(){
        return this.$store.state.name
    }
 },
复制代码

state总结:用来存放组件之间共享的数据,它跟组件的data选项类似,只不过data选项是用来存放组件的私有数据。

Getter

现在假设逻辑有变,我们最终期望得到的数据(computed中的getName),是基于 this.$store.state.name 上经过复杂计算得来的,刚好这个getName要在好多个地方使用,那么我们就得复制好几份。

vuex 给我们提供了 getter来解决这个问题,可以认为是 store 的计算属性,请看代码:

文件位置 /src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
 // 类似 vue 的 data
 state: {
  name: 'oldName'
 },
 // 类似 vue 的 computed -----------------以下5行为新增
 getters:{
  getReverseName: state => {
    return state.name.split('').reverse().join('')
  }
 },
 // 类似 vue 里的 mothods(同步方法)
 mutations: {
  updateName (state) {
   state.name = 'newName'
  }
 }
})
复制代码

然后我们可以这样使用:

文件位置 /src/App.vue

computed:{
  getName(){
   return this.$store.getters.getReverseName
  }
}
复制代码

事实上, getter 不止单单起到封装的作用,它还跟vue的computed属性一样,会缓存结果数据,只有当依赖改变的时候,才要重新计算。

getter总结:getters主要是用来过滤和重组,这些事件最好也是能在计算属性中完成,用于监听事件变化的。

Mutation

Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type) 和 一个 回调函数 (handler),且必须是同步方法。

mutation定义:

mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
复制代码

mutation使用:

this.$store.commit('increment', {
  amount: 10
})
复制代码

mutations总结:

  • 在 Vuex store 中,实际改变 状态(state) 的唯一方式是通过 提交(commit) 一个 mutation
  • mutations下的函数接收state作为参数,另一个参数叫做payload(载荷),payload是用来记录开发者使用该函数的一些信息,比如说提交了什么,提交的东西是用来干什么的,包含多个字段,所以载荷一般是对象(其实这个东西跟git的commit很类似)
  • 还有一点需要注意,mutations方法必须是同步方法!

Action

细心的你,一定发现我之前代码里 mutations 头上的注释了 类似 vue 里的 mothods(同步方法)。

为什么要在 methods 后面备注是同步方法呢? 因为mutation只能是同步的函数,只能是同步的函数,只能是同步的函数!!!

那么如果我们想触发一个异步的操作呢?答案是: action + $dispatch, 我们继续修改store/index.js下面的代码。

文件位置 /src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
 // 类似 vue 的 data
 state: {
  name: 'oldName'
 },
 // 类似 vue 的 computed
 getters:{
  getReverseName: state => {
    return state.name.split('').reverse().join('')
  }
 },
 // 类似 vue 里的 mothods(同步方法)
 mutations: {
  updateName (state) {
   state.name = 'newName'
  }
 },
 // 类似 vue 里的 mothods(异步方法) -------- 以下7行为新增
 actions: {
  updateNameAsync ({ commit }) {
   setTimeout(() => {
    commit('updateName')
   }, 1000)
  }
 }
})
复制代码

然后我们可以再我们的vue页面里面这样使用:

文件位置 /src/App.vue

methods: {
  rename () {
    this.$store.dispatch('updateNameAsync')
  }
}
复制代码

actions总结:

  • actions的作用其实和mutations是没有差别的,无非就是一个同步、异步的差别罢了。而在功能上面主要有一下两个区别:

    • actions 提交的是mutations,而不是直接变更状态。也就是说,actions会通过mutations,让mutations帮他提交数据的变更

    • actions 可以包含任意异步操作。ajax、setTimeout、setInterval不在话下

    • actions第一个参数是一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters,但是 context 对象不是 store 实例本身。下图是我从控制台打印出来的context对象

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章