vuex交互要用vuex嘛_正确有效的使用Vuex的方法:第一部分

vuex交互要用vuex嘛

从本文开始,我们将开始一系列有关Vue.js技术的出版物,并尝试从不同的实际角度确定应用程序开发及其所有组件。 在这一部分中,我们将告诉您Vuex库是什么,并详细分析诸如存储,状态,获取器,变异和动作之类的组件。

此外,在第二部分中,我们将考虑Vuex Storage的模块,应用程序结构,插件,严格模式,使用表格,测试以及优势/优势。

什么是VUEX,在哪里使用?

VueX是一个受Flux,Redux和Elm架构启发的状态管理库,但经过专门设计和调整,可以与Vue.js很好地集成并利用Vue的React性。

什么是状态管理模式? 让我们从一个实现计数器的简单Vue应用程序开始。 此独立应用程序包括以下部分:

  • 控制应用程序的状态;
  • 视图是声明式指定的状态显示;
  • 操作是响应用户与视图的交互来更改应用程序状态的可能方法。

有时可能会出现几个基于相同状态的组件:

  • 多个视图可能取决于应用程序状态的同一部分;
  • 来自不同视图的操作会影响应用程序状态的相同部分。

解决第一个问题,您将必须将具有输入参数的相同数据传输到深度嵌入的组件中。 这通常是复杂且乏味的,但是对于相邻元素而言,这根本不起作用。 解决第二个问题,您可以使用诸如引用父/子实例的解决方案,或尝试通过操作更改和同步多个状态副本。 两种方法都很脆弱,并且很快导致出现无法支持的代码。

那么,为什么不从组件中取出应用程序的总体状态,并在全局单例中进行管理呢? 同时,我们的组件树成为一个很大的“视图”,任何组件都可以访问应用程序状态或触发更改状态的操作,无论它们在树中的位置!

通过清楚地定义和分离状态管理中出现的概念,并通过要求某些规则来维持视图和状态之间的独立性,我们可以更好地构造代码并使其更易于维护。

这是Vuex的核心思想,灵感来自Flux,Redux和Elm Architecture。 与其他模式不同,Vuex被实现为为Vue.js明确设计的库,以使用其React性系统进行有效更新。

VUEX的主要组件和功能

商店

任何Vuex应用程序的中心都是商店。 存储是用于存储应用程序状态的容器。 两点将Vuex存储区与一个简单的全局对象区分开:

Vuex存储是React性的。 当Vue组件依赖其状态时,如果商店的状态发生变化,它们将被有效地更新。您不能直接更改商店的状态。 进行更改的唯一方法是显式导致突变。 这样可以确保状态的任何变化都留下标记,并允许使用工具更好地了解应用程序的进度。

安装Vuex之后,将创建一个存储库。 这非常简单,您需要指定初始状态对象以及一些操作和变异。

const store = new Vuex.Store({
  state : {
    counter : 0 // initial store state
  },
  actions : {
    increment({ commit, dispatch, getters }) {
       commit( 'INCREMENT' )
    },
    decrement({ commit, dispatch, getters }) {
       commit( 'DECREMENT' )
    }
  },
  mutations : {
    INCREMENT(state) {
      state.counter++
    },
    DECREMENT(state) {
      state.counter--
    }
  },
  getters : {
    counter(state) {
      return state.counter
    }
  }
})

我们提交突变而不是直接更改store.state.count的原因是因为我们要显式跟踪它。 这个简单的约定使您的意图更加明确,以便您在阅读代码时可以更好地推断应用程序中的状态更改。 另外,这使我们有机会实现可以记录每个突变,拍摄状态快照甚至执行时间旅行调试的工具。

州。 单州树

当一个对象包含应用程序的整个全局状态并用作唯一的源时,Vuex使用单个状态树。 这也意味着该应用将只有一个这样的存储。 单个状态树使查找所需的零件或为应用程序的当前状态制作快照方便进行调试。

您存储在Vuex中的数据遵循与Vue实例中的data相同的规则,即状态对象必须是纯文本。 那么,我们如何在Vue组件的商店内部显示状态? 由于Vuex存储是React型的,因此从其中“检索”状态的最简单方法就是从计算属性中返回某些存储状态。

每当store.state.count更改时,它将导致重新计算属性,并触发关联的DOM更新。

此模式使组件依赖于全局商店单例。 使用模块系统时,它要求在使用存储状态的每个组件中导入存储,并且在测试组件时还需要模拟。 Vuex提供了一种机制,可通过$store选项将$store从根组件“注入”到所有子组件中(由Vue.use(Vuex)启用)

export default {
  methods : {
    incrementCounter() {
      this .$store.dispatch( 'increment' )
    }
  }
}

当组件需要使用多个存储状态属性或getter时,声明所有这些计算的属性会变得重复和冗长。 为了解决这个问题,我们可以利用mapState帮助器为我们生成计算的getter函数,从而节省了一些击键:

import { mapState } from 'vuex' ;

export default {
  computed : {
    ...mapState({
       counter : state => state.counter
    }),

    counterSquared() {
      return Math .pow( this .counter, 2 )
    }
  }
}

当映射的计算属性的名称与状态子树名称相同时,我们还可以将字符串数组传递给mapState

请注意, mapState返回一个对象。 我们如何将其与其他本地计算属性结合使用? 通常,我们必须使用实用程序将多个对象合并为一个,以便可以将最终对象传递给computed 。 但是,使用对象散布运算符(这是ECMAScript的第4阶段建议),我们可以大大简化如上所示的语法。

使用Vuex并不意味着您应该将所有状态都放入Vuex。 尽管将更多状态添加到Vuex中可以使您的状态突变更明确和可调试,但有时它还可以使代码更冗长和间接。 如果一个状态严格地属于单个组件,那么将其保留为本地状态就可以了。 您应该权衡取舍,并做出适合您应用程序开发需求的决策。

礼物

有时我们可能需要根据存储状态来计算派生状态,例如,通过一系列项目进行过滤并对其进行计数。

如果需要使用多个组件,则必须复制该函数,或者将其提取到共享帮助器中,然后将其导入多个位置-两者都不理想。

Vuex允许我们在商店中定义“获取器”。 您可以将它们视为商店的计算属性。 像计算的属性一样,getter的结果将基于其依赖项进行缓存,并且仅在其某些依赖项发生更改时才会重新评估。

// In store
getters: {
  counter(state) {
    return state.counter
  },
  counterSquared(state) {
    return Math .pow(state.counter, 2 )
  }
}

// In component
import { mapGetters } from 'vuex' ;

export default {
  computed : {
    ...mapgetters([ 'counter' , 'counterSquared' ])
  }
}

您还可以通过返回函数将参数传递给getter。 当您要查询存储中的数组时,此功能特别有用。 请注意,通过方法访问的getter会在您每次调用它们时运行,并且结果不会被缓存。

mapGetters帮助器只是将商店的mapGetters映射到本地计算的属性。

突变

实际更改Vuex存储中状态的唯一方法是提交突变。 Vuex突变与事件非常相似:每个突变都有一个字符串类型和一个处理程序。 处理函数是我们执行实际状态修改的地方,它将接收状态作为第一个参数。

您不能直接调用变异处理程序。 认为它更像事件注册:

“当触发类型为“ increment”的突变时,请调用此处理程序。

要调用变异处理程序,您需要使用其类型调用store.commit

export default {
  methods : {
    incrementCounter() {
      this .$store.commit( 'INCREMENT' )
    }
  }
}

您可以将另一个参数传递给store.commit ,称为变体的有效负载。 在大多数情况下,有效负载应该是一个对象,以便它可以包含多个字段,并且记录的突变也将更具描述性。 提交突变的另一种方法是直接使用具有type属性的对象。 使用对象样式提交时,整个对象将作为有效负载传递给变异处理程序,因此处理程序保持不变。

由于Vue使Vuex存储的状态具有React性,因此当我们更改状态时,观察状态的Vue组件将自动更新。 这也意味着在使用普通Vue时,Vuex突变会受到相同的React性警告:

  • 优先使用所有需要的字段来初始化商店的初始状态。
  • 在向对象添加新属性时,您应该-使用Vue.set(obj, 'newProp', 123) ,或用一个新的对象替换该对象。 例如,使用对象传播语法。

但是,使用常量指示突变类型是完全可选的,尽管这在大型项目中可能很有用。

要记住的一个重要规则是,变异处理函数必须是同步的。 想象我们正在调试应用程序,并查看devtool的突变日志。 对于记录的每个突变,devtool将需要捕获状态的“之前”和“之后”快照。 但是,上面的示例突变中的异步回调使这成为不可能:在提交突变时尚未调用该回调,并且devtool无法知道何时将实际调用该回调-回调中执行的任何状态突变本质上是无法追踪的!

您可以使用this.$store.commit('xxx')提交组件中的突变,或使用mapMutations帮助程序将组件方法映射到store.commit调用(需要$store根注入)

异步与状态突变相结合会使您的程序难以推理。 例如,当您同时使用两个使状态发生变化的异步回调来调用两个方法时,您如何知道何时调用它们以及首先调用哪个回调? 这正是将两个概念分开的原因。 在Vuex中,变异是同步事务。 要处理异步操作,应删除动作。

动作

动作类似于突变,但有一些区别:

  • 动作不会改变状态,而是执行突变。
  • 动作可以包含任意异步操作。
actions: {
  signIn({ commit }, payload) {// Show spinner when user submit form
    commit( 'LOGIN_IN_PROGRESS' , true );
    
    // axios - Promise based HTTP client for browser and node.js
    axios
      .post( '/api/v1/sign_in' , {
        email : payload.email
        password: payload.password
      })
      .then( ( response ) => {
         const { user, token } = response.data;
         commit( 'SET_AUTH_TOKEN' , token);
         commit( 'SET_USER' , user);
         commit( 'LOGIN_IN_PROGRESS' , false );
      })
      .catch( ( error ) => {
        commit( 'SET_SIGN_IN_ERROR' , error.response.data.reason);
        commit( 'LOGIN_IN_PROGRESS' , false );
      })
  }
}

动作处理程序会收到一个上下文对象,该对象在商店实例上公开了相同的方法/属性集,因此您可以调用context.commit更改,或者通过context.statecontext.getters访问状态和获取方法。 我们甚至可以使用context.dispatch调用其他动作。 稍后介绍模块时,我们将看到为什么此上下文对象不是商店实例本身。

在实践中,我们经常使用ES2015参数解构来简化代码,尤其是当我们需要多次调用commit 。 使用store.dispatch方法触发动作。 如果我们想增加计数,乍一看可能看起来很愚蠢,为什么不直接调用store.commit('increment')呢? 还记得突变必须是同步的吗? 动作不行。 我们可以在一个动作中执行异步操作。 动作支持相同的有效负载格式和对象样式分派。

实际操作的一个更实际的示例是结帐购物车的操作,该操作涉及调用异步API并提交多个突变。 执行异步操作流程,并通过提交动作来记录动作的副作用(状态突变)。

您可以使用this.$store.dispatch('xxx')调度组件中的动作,也可以使用mapActions帮助器将组件方法映射到store.dispatch调用(需要$store根注入)。 动作通常是异步的,那么我们如何知道动作何时完成? 更重要的是,我们如何将多个动作组合在一起以处理更复杂的异步流?

首先要知道的是store.dispatch可以处理由触发的操作处理程序返回的Promise,并且还返回Promise。 store.dispatch可能在不同模块中触发多个动作处理程序。 在这种情况下,返回的值将是一个Promise,它在所有触发的处理程序都已解决时会解决。

这只是我们在下一篇有关Vue.js及其所有其他工具和优点的文章中所要讲述的一小部分。 接下来,我们继续对Vuex库和组件进行回顾。

另外,在我们的博客中,您可以阅读有关Vue.js的更多信息: https ://amoniac.eu/blog/post/why-we-fell-in-love-with-vue-j

先前发布在 https://amoniac.eu/blog/post/correct-and-efficiency-vuex-using-part-i

翻译自: https://hackernoon.com/correct-and-efficient-way-to-use-vuex-part-i-wf15432eu

vuex交互要用vuex嘛

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值