Vue共享数据模式 VueX

前言

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

举一个简单的例子,都知道父子组件通信,那么兄弟组件通信怎么办那?可能有人想到先把子组件的数据传递到父组件中,然后兄弟组件接收父组件中的数据。诚然这样的方式确实可以实现我们的需求,可要是嵌套的过多的话,那么麻烦吗?答案是肯定的!
简单来说,VueX 可以帮助我们共享数据,和组件一样,实现复用。

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

安装

直接下载 / CDN 引用

https://unpkg.com/vuex 提供了基于 NPM 的 CDN 链接。以上的链接会一直指向 NPM 上发布的最新版本。也可以通过 https://unpkg.com/vuex@2.0.0 这样的方式指定特定的版本。

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuex@3.6.0/dist/vuex.js"></script>

在 Vue 之后引入 vuex 会进行自动安装,注意:VueX要在Vue之后引用。

NPM

npm install vuex --save

YARN

yarn add vuex

模块化引用

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

Vue.use(Vuex)

state 存放状态

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

以上就是一个简单的Store实例,通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过this.$store访问到。通常数据都存放在state中,访问的话不能直接引用这个value,而是通过this.$store.state.value

<body>
<div id="app">
    {{this.$store.state.msg}}
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuex@3.6.0/dist/vuex.js"></script>
<script>
    const store = new Vuex.Store({
        state: {
            count: 999999,
            msg:"mssage"
        }
    })
    new Vue({
        el: '#app',
        store: store
    })
</script>
</body>

在实例中注册后就可以使用了,基本和data中的数据一样,可以在任何组件中直接调用。当然不要直接使用this.$store.state.value修改数据,因为是共享的,直接修改对项目不易维护,建议使用下面几个部分修改。

getters 加工state成员给外界

这个就和computed 有一点类似,它不是把数据直接返回,而是对数据加工后,返回一个新的数据。保持state数据不变。

<div id="app">
    <p>{{this.$store.getters.format}}</p>
    <button  @click="add">button</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuex@3.6.0/dist/vuex.js"></script>
<script>
    const store = new Vuex.Store({
        state: {
            count: 999999,
            msg:"mssage"
        },
        getters:{
            format(store){
                return store.msg+"PDDDDDD!"
            }
        }
    })
    var app = new Vue({
        el: '#app',
        store: store,
        methods: {
            add(){
                this.$store.commit('add',10)
            }
        }
    })
</script>
</body>

除此之外,可以通过返回一个函数进行数据传参:

getters: {
  // ...
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}

store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果

mutations 操作state

这个属性和methods属性是一样的,都是定义的方法。使用流程是,在methods中通过this.$store.commit('function', 'arguments')进行调用:

<div id="app">
    {{this.$store.state.msg}}
    {{this.$store.state.count}}
    <button  @click="add">button</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuex@3.6.0/dist/vuex.js"></script>
<script>
    const store = new Vuex.Store({
        state: {
            count: 999999,
            msg:"mssage"
        },
        mutations: {
            add (state,n) {
                state.count+=n
            }
        }
    })
    var app = new Vue({
        el: '#app',
        store: store,
        methods: {
            add(){
                this.$store.commit('add',10)
            }
        }
    })
</script>

commit第二个参数不光光是简单的数据类型,还可以是一个对象,这样就能进行多个数值的传递了。提交 mutation 的另一种方式是直接使用包含 type 属性的对象:

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

还有一点比较重要:mutations 必须是同步函数,这一点主要考虑了devtools 调试工具,异步操作并不能实时更新mutations中的数据 ,这会给我们带来麻烦。

actions 异步操作

Action 类似于 mutation,不同在于:

  1. Action 提交的是 mutation,而不是直接变更状态
  2. Action 可以包含任意异步操作
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此可以调用 context.commit 提交一个 mutation,或者通过 context.statecontext.getters 来获取 state 和 getters。
Action 通过 store.dispatch 方法触发:

store.dispatch('increment')

异步操作:

actions:{
    aEdit(context,payload){
        setTimeout(()=>{
            context.commit('edit',payload)
        },2000)
    }
}

// 在组件中调用
this.$store.dispatch('aEdit',{age:15})

组合 Action:

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}
// 调用
store.dispatch('actionA').then(() => {
  ...
})

modules 模块化状态管理

当项目庞大,状态非常多时,可以采用模块化管理模式。Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。

models:{
    a:{
        state:{},
        getters:{},
        ....
    }
}

组件内调用模块a的状态:

this.$store.state.a

而提交或者dispatch某个方法和以前一样,会自动执行所有模块内的对应type的方法:

this.$store.commit('editKey')
this.$store.dispatch('aEditKey')

虽然是模块化了,但是最终渲染的时候还是只有一个Store实例,这个要知道

项目结构

Vuex 不限制代码结构。但是规定了一些需要遵守的规则:

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

只要你遵守以上规则,如何组织代码随你便。如果 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。
对于大型应用,可以把 Vuex 相关代码分割到模块中。下面是项目结构示例:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值