问题背景

为什么要用 vuex?

在使用 Vue 进行组件化开发时,组件通信是一个十分重要的部分。在 Vue 中,父子组件的关系可以总结为

  • 父子组件通信:父组件通过 props 向下传递数据给子组件
  • 子父组件通信:子组件通过 events 给父组件发送消息

    • 使用 $on(eventName) 监听事件
    • 使用 $emit(eventName) 触发事件
  • 非父子组件通信:使用一个空的 Vue 实例作为中央事件总线

父子,子父 组件之间的通信是很轻松的,通过 props 和 events 即可实现;但是往往我们的应用可能不只有这么简单的层级关系,在多层跨级组件如果通过 props 去传递,那意味着一层一层的往子组件传递,最终你可能不知道当前组件的数据最终来自哪个父组件(当然你可以逆着方向一层一层往上找),通过 events 事件机制显然也存在着类似的问题。如果你觉得这样也可以接受,你可能不需要 Vuex;但如果你在想有没有什么好的模式优雅的去解决,你可以继续阅读下面的部分。

状态管理

我们通过发送 action,提交 mutation 的方式,而非直接改变 store.state.count,是因为我们想要更明确地追踪到状态的变化。这个简单的约定能够让你的意图更加明显,这样你在阅读代码的时候能更容易地解读应用内部的状态改变。此外,这样也让我们有机会去实现一些能记录每次状态改变,保存状态快照的调试工具。有了它,我们甚至可以实现如时间穿梭般的调试体验。由于 store 中的状态是响应式的,在组件中调用 store 中的状态简单到仅需要在计算属性中返回即可。触发变化也仅仅是在组件的 methods 中提交 mutations。

  • actions:操作行为处理模块。负责处理 Vue Components 接收到的所有交互行为。包含同步/异步操作,向后台 API 请求的操作就在这个模块中进行,包括触发其他 action 以及提交 mutation 的操作。该模块提供了 Promise 的封装,以支持 action 的链式触发。
  • mutations:状态改变操作方法。是 Vuex 修改 state 的唯一推荐方法,其他修改方式在严格模式下将会报错。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些 hook 暴露出来,以进行 state 的监控等。
  • state:页面状态管理容器对象。集中存储 Vue components 中 data 对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用 Vue 的细粒度数据响应机制来进行高效的状态更新。
  • getters:state 对象读取方法。Vue Components 通过该方法读取全局 state 对象。

数据流转

用 getters 将 state 数据映射到当前组件,在 vue component 中发送 action,在 action 中请求数据,并调用 mutations,mutationg 改变 state 的数据,从而实现数据更新导致的页面更新。

问题描述

在正在做的项目中遇到这样一个问题,当页面进行分页请求时,连续点击当前页会一直发送请求,极大的降低了性能,于是决定减少请求次数,只有 pageNum 发生变化时才去请求。

实现过程

vue 中有 watch 这个 api 它可以监听对象及对应值的变化从而在数据发生变化时调用 action,于是写了如下代码

实现分页操作的绑定事件

@redirect="handlePageRedirect"

发送 action 将点击的 pageNum 存储在 state 里 image监听 pageNum 的变化来发送 action 来请求数据,当然还需通过 computed 将 state 里需要监听的数据映射到当前组件 image

发现数据并没有被监听,并尝试打印监听的数据,代码如下

watch: {
    'aList.pageNum'(newVal, oldVal) {
        console.log(newVal,oldVal);
    }
}

问题定位

打开调试工具,发现 state 数据中并没有 pageNum 这个数据,但在文件 state.js 中是有默认值的,查找发现,在 mutations 中将原本 state 的默认值覆盖 state.js 中监听的数据 image在 mutations 中将 state 数据覆盖代码,代码如下

state.aList = {
    list: data.list,
    total: data.total,
    pageSize: data.pageSize
}

查阅资料了解到 mutation 改变 state 数据只需要将新值加入到原来对象,而不是覆盖它,代码如下 image
故修改代码为

state.aList = {
    ...state.aList,
    ...data
}

总结知识

watch 监听的方式

  • 对象中属性的 watch
watch: {
    'aList.pageNum'(newVal, oldVal) {
        console.log(newVal,oldVal);
    }
}
  • 某个对象的 watch imagetips: 只要 bet 中的属性发生变化(可被监测到的),便会执行 handler 函数;如果想监测具体的属性变化,如 pokerHistory 变化时,才执行 handler 函数,则可以利用计算属性 computed 做中间层。 如果想监测具体的属性变化,如 pokerHistory 变化时,才执行 handler 函数,则可以利用计算属性 computed 做中间层。 注意 deep: true 必须加。
  • 监听url的变化发送请求(可获取url上参数)
watch: {
        $route({ query }) {
            this.searchUser([
                {},
                {
                    appId: query.appId
                }
            ]);
        }
    }
  • mutations 中改变数据的方式,将新值与容器中的值合并,并不是直接覆盖。
  • watch 暂且写到这里,欢迎大家来补充留言。
Logo

前往低代码交流专区

更多推荐