不要滥用Pinia和Redux了!多组件之间交互可以手写一个调度器!

简介: 【8月更文挑战第24天】不要滥用Pinia和Redux了!多组件之间交互可以手写一个调度器!

前言

vue2的vuex、和vue3的Pinia或者react的Redux,相信大家一定不陌生!在很多情况下,两个几乎不关联的组件之间通信,我们大多都会使用这些状态管理工具完成。

假设有下面的一个场景,我们需要再C组件点击一个按钮,请求一个数据,然后在发送给E组件,E组件执行一些逻辑处理。

image.png
如果我们的系统比较庞大,模块众多,选择Pinia是一个非常便捷的方式!但如果我们整个系统比较小,不同模块之间交互的情况不多,为了一个简单的功能引入Pinia是非常不划算的!

为了完成上面的需求,我们的代码必须这么写
首先,我们需要安装和设置Pinia,然后,我们创建一个 Pinia store 来管理数据。

// store.js
import {
   
    createPinia } from 'pinia';

const pinia = createPinia();

export const useDataStore = pinia.store('data', {
   
   
  state: () => ({
   
   
    data: null,
  }),
  actions: {
   
   
    fetchData() {
   
   
      // 在这里发起接口请求获取数据,这里使用一个假的示例数据
      const fakeData = '这是从接口获取的数据';
      this.data = fakeData;
    },
  },
});

export default pinia;

接下来,我们创建 C 组件来触发数据请求。

<template>
  <button @click="fetchData">请求数据</button>
</template>

<script>
import {
   
    defineComponent } from 'vue';
import {
   
    useDataStore } from './store';

export default defineComponent({
   
   
  setup() {
   
   
    const dataStore = useDataStore();

    const fetchData = () => {
   
   
      dataStore.fetchData();
    };

    return {
   
   
      fetchData,
    };
  },
});
</script>

最后,我们创建 E 组件来接收数据并进行逻辑处理。

<template>
  <div>
    <p v-if="data">{
   
   {
   
    data }}</p>
    <p v-else>暂无数据</p>
  </div>
</template>

<script>
import {
   
    defineComponent } from 'vue';
import {
   
    useDataStore } from './store';

export default defineComponent({
   
   
  setup() {
   
   
    const dataStore = useDataStore();

    // 从 store 中获取数据
    const data = dataStore.data;

    return {
   
   
      data,
    };
  },
});
</script>

我们仅仅为了一个很小的功能,引入了Pinia,非常不划算!费事费力!

使用事件调度器优化代码

假设我们现在有个事件调度器,可以实现数据绑定与监听,它的用法是这样的

const dispatcher = new EventDispatcher()

// 绑定事件
dispatcher.addEventListener("patcher1",(res) => {
   
   
  // 监听到的数据
  console.log(res);
})

dispatcher.dispatchEvent('patcher1',"发送的数据")

我们用这个dispatcher优化上述的逻辑代码

/* C组件 */
<template>
  <button @click="fetchData">请求数据</button>
</template>

<script setup>
const fetchData = () => {
   
   
  dispatcher.dispatchEvent('patcher1',"发送的数据")
};
</script>
<template>
  <div>
    <p v-if="data">{
   
   {
   
    data }}</p>
    <p v-else>暂无数据</p>
  </div>
</template>

<script>
const data = ref("");

// 绑定事件
dispatcher.addEventListener("patcher1",(res) => {
   
   
  // 监听到的数据
  data.value = res
})
</script>

可以看到,同样的逻辑,我们使用dispatcher代码更加简洁!避免了引入pinia,不仅减少了代码体积,还让代码写起来更加简单!

可见,一些简单的场景,如整个系统之间只有个别组件之间存在交互,引入pinia或者redux等状态管理工具是非常不划算的!!

你可能会有疑惑,不是需要引入EventDispatcher这个类吗?这个类难道不复杂?体积不大?

事实上,这个类的代码也就十几行,完全可以手写,以后粘贴复制!

实现EventDispatcher事件调度器

我们这个EventDispatcher其实功能很简单,就是数据监听,数据绑定,移除事件三个功能。
它的使用方法应该如下

const dispatcher = new EventDispatcher()

// 绑定第一个一个事件
dispatcher.addEventListener("patcher1",(res) => {
   
   
  // 监听到的数据
  console.log(res);
})

// 绑定第二个事件
dispatcher.addEventListener("patcher2",(res) => {
   
   
  // 监听到的数据
  console.log(res);
})

// 触发第一个事件
dispatcher.dispatchEvent('patcher1',"发送的数据")
// 触发第二个事件
dispatcher.dispatchEvent('patcher2',"发送的数据")

//移除第一个事件
dispatcher.removeEventListener('patcher1')
//移除第二个事件
dispatcher.removeEventListener('patcher2')

要想实现这个功能,我们需要创建一个事件调度器EventDispatcher类,这个类的结构如下

export class EventDispatcher  {
   
   
    // 储存所有监听的事件
    private listeners = {
   
   };
    // 绑定事件的方法
    protected addEventListener(type: string, listener: Function) {
   
   

    }
    // 移除事件的方法
    protected removeEventListener(type: string) {
   
   

    }
    // 触发事件的方法
    protected dispatchEvent(type: string, data: any) {
   
   

    }
}

我们完善其内部方法

export class EventDispatcher{
   
   
    private listeners: {
   
    [type: string]: Function[] } = {
   
   };

    protected addEventListener(type: string, listener: Function) {
   
   
        if (!this.listeners[type]) {
   
   
            this.listeners[type] = [];
        }
        if (this.listeners[type].indexOf(listener) === -1) {
   
   
            this.listeners[type].push(listener);
        }
    }
    protected removeEventListener(type: string) {
   
   
        this.listeners[type] = [];
    }

    protected dispatchEvent(type: string, data: any) {
   
   
        const listenerArray = this.listeners[type] || [];
        if (listenerArray.length === 0) return;
        listenerArray.forEach(listener => {
   
   
            listener.call(this, data);
        });
    }
}
  • listeners用于存储事件类型与对应监听器数组的映射。它是一个对象,键是事件类型(type),值是监听器函数数组。
  • addEventListener用于添加事件监听器。它接受两个参数:事件类型(type)和监听器函数(listener)。如果当前事件类型尚未有对应的监听器数组,则创建一个空数组。然后,将传入的监听器函数添加到该数组中,但仅当该监听器函数不在数组中时才添加。
  • dispatchEvent用于触发指定类型的事件,并传递相应的数据。它接受两个参数:事件类型(type)和要传递的数据(data)。首先,它从存储的监听器数组中获取与事件类型匹配的监听器数组。然后,遍历该数组,依次调用每个监听器函数,并传递数据作为参数。
  • removeEventListener这是一个受保护的方法,用于移除指定类型的所有事件监听器。它接受一个参数:事件类型(type)。当调用该方法时,它会将指定类型的监听器数组清空。

上述代码实现了一个简单的事件调度器,它的核心原理是使用了一个对象 listeners 来存储事件类型和对应的监听器函数数组。当调用 addEventListener 方法添加监听器时,它会将监听器函数添加到对应事件类型的监听器数组中。当调用 dispatchEvent 方法触发事件时,它会获取对应事件类型的监听器数组,并依次调用每个监听器函数。而 removeEventListener 方法则用于移除指定类型的所有监听器。

如果你想在全局任意的地方使用这个数据调度器,我们只需要将它绑定在window对象上即可!
在我们的程序入口文件里进行挂载

const dispatcher = new EventDispatcher()
window.myDispatcher = dispatcher

现在,你可以在任何地方开心的使用这个方法了!简单的场景再也不用引入麻烦的pinia或者redux了!

总结

本教程中,基于简单业务不同组件之间交互的场景,我们使用手写的事件调度器EventDispatcher替代了pinia或者redux等状态管理工具,不仅简化了代码,还优化了项目体积,还让自己的代码更有逼格!相信大家看完一定有所收获!也欢迎大家能给出自己的建议,帮助他人哈!

相关文章
|
3月前
|
存储 前端开发 索引
REACT 在组件之间共享状态
REACT 在组件之间共享状态
|
4月前
|
JavaScript 前端开发 数据管理
第三十四章 使用react-redux进一步管理状态
第三十四章 使用react-redux进一步管理状态
|
4月前
|
JavaScript 前端开发 开发者
Vue的事件处理机制提供了灵活且强大的方式来响应用户的操作和组件间的通信
【5月更文挑战第16天】Vue事件处理包括v-on(@)指令用于绑定事件监听器,如示例中的按钮点击事件。事件修饰符如.stop和.prevent简化逻辑,如阻止表单默认提交。自定义事件允许组件间通信,子组件通过$emit触发事件,父组件用v-on监听并响应。理解这些机制有助于掌握Vue应用的事件控制。
49 4
|
1月前
|
前端开发 JavaScript 算法
深入剖析React状态管理的优势与局限
【8月更文挑战第20天】
74 3
|
1月前
|
设计模式 JavaScript 安全
MobX状态管理:简洁而强大的状态机
MobX 是一种简洁高效的状态管理库,通过声明式的方式管理应用状态,使数据变化自动同步到视图。它利用 `@observable` 创建响应式数据,`@computed` 实现自动更新的计算属性,`@action` 确保状态安全变更。结合 `mobx-react`,可在 React 组件中使用 `observer` 自动响应状态更新。MobX 内部采用代理与访问者模式追踪依赖,确保最小化更新,提升性能。支持 TypeScript,提供类型安全与代码提示。
45 2
|
20天前
|
前端开发 JavaScript API
掌握React表单管理的高级技巧:探索Hooks和Context API如何协同工作以简化状态管理与组件通信
【8月更文挑战第31天】在React中管理复杂的表单状态曾是一大挑战,传统上我们可能会依赖如Redux等状态管理库。然而,React Hooks和Context API的引入提供了一种更简洁高效的解决方案。本文将详细介绍如何利用Hooks和Context API来优化React应用中的表单状态管理,通过自定义Hook `useForm` 和 `FormContext` 实现状态的轻松共享与更新,使代码更清晰且易于维护,为开发者带来更高效的开发体验。
25 0
|
20天前
|
前端开发
|
20天前
|
存储 JavaScript 前端开发
探索React状态管理:Redux的严格与功能、MobX的简洁与直观、Context API的原生与易用——详细对比及应用案例分析
【8月更文挑战第31天】在React开发中,状态管理对于构建大型应用至关重要。本文将探讨三种主流状态管理方案:Redux、MobX和Context API。Redux采用单一存储模型,提供预测性状态更新;MobX利用装饰器语法,使状态修改更直观;Context API则允许跨组件状态共享,无需第三方库。每种方案各具特色,适用于不同场景,选择合适的工具能让React应用更加高效有序。
32 0
|
4月前
|
前端开发 JavaScript 开发者
在React中,如何利用生命周期方法管理组件的状态和行为?
【5月更文挑战第29天】在React中,如何利用生命周期方法管理组件的状态和行为?
42 3
|
4月前
|
前端开发 JavaScript
深入理解React中的useReducer:管理复杂状态逻辑的利器
深入理解React中的useReducer:管理复杂状态逻辑的利器