前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue 全家桶学习笔记:Vuex

Vue 全家桶学习笔记:Vuex

作者头像
Chor
发布2019-11-26 14:22:10
6680
发布2019-11-26 14:22:10
举报
文章被收录于专栏:前端之旅前端之旅

1. 为什么要使用 Vuex?

来自 官方文档 的介绍:

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

开发中,多个组件很可能会共享同一个状态(包括状态和数据),而组件和组件之间可能是兄弟关系,也可能是复杂的多层嵌套关系,如果单靠组件通信完成状态变更和同步,事情会变得很麻烦:

但是有了 Vuex 后,我们可以用它保管公共的状态,每当组件想要访问或者修改共享状态的时候,直接与 Vuex 进行交互就可以,而组件与一个“状态容器”的交互,比起前面的通信是要简单很多的:

2. 安装和使用

安装和 vue-router 是差不多的:

npm install vuex --save

之后,项目的 src 文件夹下会多出 store 文件夹。里面存放的 store.js 可以配置 Vuex(没有的话可以手动创建),大概结构是这样的:

// store.js

import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)

const store = new Vuex.Store({
    state:{...},
    getters:{...},
    mutations:{...},
     actions:{...},
    modules:{...}         
})

export default store

接着,在 main.js 中 引入 Vuex,并在 Vue 根实例下注册。

下面介绍 store.js 中的具体配置。

3. Vuex 的核心

Vuex 的核心包括 state、getters、mutations、actions、modules。

这几者的关系,我们可以先看来自官网的图:

2.1. state

Vuex 中的 state 相当于组件中的 data 属性。

store.js:

const store = new Vuex.Store({
    state:{
        name:'Sam'
    }
})

App.vue:

<div>{{$store.state.name}}</div>   <!--Sam-->
<hello-vuex></hello-vuex>   <!--Sam-->

<script>
import HelloVuex from './components/HelloVuex'
export default{
    components:{
        HelloVuex
    }
}
</script>

HelloVuex.vue:

<div>{{$store.state.name}}</div>   

<script>
export default{

}
</script>
2.2. getters

Vuex 中的 getters 相当于组件中的 computed 属性。getters 里面的方法接受两个参数,一个是 state ,我们通过它拿到 state 里的数据进行修改;一个是 getters。

const store = new Vuex.Store({
    state:{
        name:'Sam'
    },
    getters:{
        change(state){
            return state.name + 'and Jack'
        }
    }
})
<div>{{$store.getters.change}}</div>  <!--Sam and Jack-->

有时候,我们可能需要在外面传参,但是 getters 里面的方法只接受两个参数,这时候可以考虑让函数返回一个闭包 :

const store = new Vuex.Store({
    state:{
        name:'Sam'
    },
    getters:{
        change(state){
            return function(string){
                return state.name + string
            }
        }
    }
})
<div>{{$store.getters.change('and Tom')}}</div>  <!--Sam and Tom-->
2.3. mutations

Vuex 中的 mutations 相当于组件中的 methods 属性,要更改 Vuex 的 store 中的状态,唯一方法就是提交 mutation 。这里要注意,mutations 只负责处理同步的事件。

mutations 里面的方法接受两个参数,一个是 state,一个是从外面传进来的 payload(载荷),这个 payload 具体是什么,要看 commit 的风格。

下面的操作会把两个组件中的 “Sam” 都同步修改为 “Jack”:

const store = new Vuex.Store({
    state:{
        name:'Sam'
    },
    mutations:{
        change(state,payload){
            state.name = payload
        }
    }
})
<button @click="changeName">点击修改名字</button>
<div>{{$store.state.name}}</div>  
<hello-vuex></hello-vuex>  

<script>
import HelloVuex from './components/HelloVuex' 
export default {
    components:{
        HelloVuex
    }
    methods:{
        changeName(){
            this.$store.commit('change','Jack')
        }
    }
}
</script>

关于提交风格。我们可以在 commit 的时候直接传入一个对象:

<script>
export default {
    methods:{
        changeName(){
            this.$store.commit({
                type:'change',
                newName:'Jack'
            })
        }
    }
}
</script>

此时,我们接受的 payload 是提交时的这一整个对象,所以对应代码修改为:

const store = new Vuex.Store({
    state:{
        name:'Sam'
    },
    mutations:{
        change(state,payload){
            state.name = payload.newName
        }
    }
})

上面的修改是响应式的,视图和 devtools 中都能看到发生了相应的同步改变。但要注意,下面的代码不会发生响应式的改变:

const store = new Vuex.Store({
    state:{
        obj:{
            name:'Sam'
        }
    },
    mutations:{
        change(state,payload){
            state.obj.age = 24
        }
    }
})

这是因为,我们根本就没有在 obj 上初始化 age 这个属性。要做到响应式,可以修改为:

const store = new Vuex.Store({
    state:{
        obj:{
            name:'Sam'
        }
    },
    mutations:{
        change(state,payload){
            Vue.set(state.obj,age,24)
        }
    }
})
2.4. actions

mutations 中的方法必须是同步的,这样 devtools 才可以进行追踪,依次捕获状态前后的快照;而异步的方法是无法追踪的,因为并不清楚回调函数的执行时机。因此,异步的方法要写在 actions 中。下面的操作可以在 2s 后将 Sam 修改为 Jack:

// store.js

state:{
    name:'Sam'
}
mutations:{
    change(state,payload){
        state.name = payload
    }
},
actions:{
   Achange(context,payload){
       setTimeout(() => {
           context.commit('change',payload)
       },2000)
   } 
}
<!-- App.vue-->

<button @click="changeName">点击修改名字</button>    
<div>{{$store.state.name}}</div> 
<hello-vuex></hello-vuex>

<script>
import HelloVuex from './components/HelloVuex' 
export default {
    components:{
        HelloVuex
    },
    methods:{
        changeName(){
            this.$store.dispatch('Achange','Jack')  // 也接受 payload 参数 
        }
    }
}
</script>

因为是异步操作,所以我们很可能需要回调一个函数告知我们异步操作的结果,这时候可以用 Promise。也就是,将 actions 中的异步操作包裹在 Promise 中,并返回这个 Promise,之后在 dispatch 后调用 then(因为 dispatch 后返回的是一个 Promise 实例)。代码如下:

// store.js

state:{
    name:'Sam'
}
mutations:{
    change(state,payload){
        state.name = payload
    }
},
actions:{
   Achange(context,payload){
       return new Promise((resolve,reject) => {
           setTimeout(() => {
              context.commit('change',payload)
              resolve()
           },2000)
       })
   } 
}
<!--App.vue-->

<button @click="changeName">点击修改名字</button>
<div>{{$store.state.name}}</div>
<hello-vuex></hello-vuex>

<script>
import HelloVuex from './components/HelloVuex' 
export default {
    components:{
        HelloVuex
    },
    methods:{
        changeName(){
            this.$store
              .dispatch('Achange','Sam')
              .then(() => {
                console.log('异步操作成功')
            })     
        }
    }
}
</script>
2.5. modules

由于使用单一状态树(单一数据源),应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决以上问题,Vuex 允许我们将 store 分割成若干个 module,每个 module 可以看作一个小的单元,它们各自都拥有自己的 state、mutations、actions、getters(甚至是 modules)。

1. state

单个 module (假定是a)最终还是会挂载到 store 的 state 上的:

所以实际上仍然还是单一状态树。可以通过 $store.state.a 拿到这个 module,再拿到它的 state。

// store.js

const moduleA = {
    state:{ age:20 }
}
const store = new Vuex.Store({
    state:{
        name:'Sam'
    },
    getters:{},
    mutations:{},
    actions:{},
    modules:{
        a: moduleA
    }
})
<!--App.vue-->

<div>{{$store.state.a.age}}</div>    <!--20-->
2 getters

用法和之前一致,首先会到 store 的 getters 下找对应方法,找不到再去单个 module 下的 getters 寻找。getters 中的方法接受的参数,一个是当前 module 下的 state,一个是当前 module 下的 getters

3 mutations

用法与之前一致,commit 的时候首先会到 store 的 mutations 下找对应方法,找不到再去单个 module 下的 mutations 寻找。

4 actions

用法和之前类似,依然是直接 dispatch,不过 actions 中的方法的参数 context 不再指向 store ,而是指向单个 module。

4. 类型常量

mutations 中的方法名实际上是一个字符串,也就是说,下面两种写法是等效的:

mutations:{
    change(){
        .....
    }
    // 等价于
    ['change'](){
        .....
    }
}

可以将所有的方法名各自用一个常量表示,并将它们写在一个统一的文件中,之后在 mutations 和 commit 中表示方法名字的时候,都用这个常量表示。

5. 项目结构

如果把所有的 mutations、getters、actions 等都放在 store.js 文件中,代码会变得很臃肿,所以我们可以进行分离。state 仍然保留在 store.js 文件中,actions、getters、mutations 分离到对应的文件中,各个 module 分离到 modules 文件夹对应的文件中。

import moduleA from './modules/moduleA'
import getters from './getters'
import actions from './actions'
import mutations from './mutations'

const store = new Vuex.Store({
  state:{...},
  getters,
  actions,
  mutations,
  modules:{
    a:moduleA
  }
})
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-11-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 为什么要使用 Vuex?
  • 2. 安装和使用
  • 3. Vuex 的核心
    • 2.1. state
      • 2.2. getters
        • 2.3. mutations
          • 2.4. actions
            • 2.5. modules
              • 1. state
              • 2 getters
              • 3 mutations
              • 4 actions
          • 4. 类型常量
          • 5. 项目结构
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档