不要滥用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等状态管理工具,不仅简化了代码,还优化了项目体积,还让自己的代码更有逼格!相信大家看完一定有所收获!也欢迎大家能给出自己的建议,帮助他人哈!

相关文章
|
5月前
|
存储 前端开发 索引
REACT 在组件之间共享状态
REACT 在组件之间共享状态
|
6月前
|
JavaScript 前端开发 数据管理
第三十四章 使用react-redux进一步管理状态
第三十四章 使用react-redux进一步管理状态
|
前端开发 调度
React(二) —— 组件间的通信方式
React(二) —— 组件间的通信方式
|
1月前
|
存储 前端开发 JavaScript
React中组件通信方式有哪些
本文首发于微信公众号“前端徐徐”,探讨了 React 组件通信的多种方式,包括 Props、回调函数、Ref、Context、Redux、消息发布-订阅和全局事件。每种方式都有其独特的优势和适用场景,如 Props 适用于简单的父子组件通信,Redux 适合复杂的状态管理。文章通过示例详细介绍了这些通信方式的实现和注意事项,帮助开发者选择最适合项目需求的通信方式。
32 2
React中组件通信方式有哪些
|
16天前
|
前端开发 JavaScript 算法
React的运行时关键环节和机制
【10月更文挑战第25天】React的运行时通过虚拟DOM、组件渲染、状态管理、事件系统以及协调与更新等机制的协同工作,为开发者提供了一种高效、灵活的方式来构建用户界面和处理交互逻辑。这些机制相互配合,使得React应用能够快速响应用户操作,同时保持良好的性能和可维护性。
|
1月前
|
前端开发 JavaScript API
React 组件通信方式
【10月更文挑战第7天】本文详细介绍了 React 应用中组件通信的基础概念、常见方式(如 props、回调函数、Context API 和 Redux)及其示例代码,同时探讨了组件通信中常见的问题与解决策略,旨在帮助开发者更好地理解和应用组件间的数据传递与交互技术。
44 2
|
6月前
|
JavaScript 前端开发 开发者
Vue的事件处理机制提供了灵活且强大的方式来响应用户的操作和组件间的通信
【5月更文挑战第16天】Vue事件处理包括v-on(@)指令用于绑定事件监听器,如示例中的按钮点击事件。事件修饰符如.stop和.prevent简化逻辑,如阻止表单默认提交。自定义事件允许组件间通信,子组件通过$emit触发事件,父组件用v-on监听并响应。理解这些机制有助于掌握Vue应用的事件控制。
67 4
|
3月前
|
前端开发 JavaScript API
掌握React表单管理的高级技巧:探索Hooks和Context API如何协同工作以简化状态管理与组件通信
【8月更文挑战第31天】在React中管理复杂的表单状态曾是一大挑战,传统上我们可能会依赖如Redux等状态管理库。然而,React Hooks和Context API的引入提供了一种更简洁高效的解决方案。本文将详细介绍如何利用Hooks和Context API来优化React应用中的表单状态管理,通过自定义Hook `useForm` 和 `FormContext` 实现状态的轻松共享与更新,使代码更清晰且易于维护,为开发者带来更高效的开发体验。
44 0
|
3月前
|
前端开发
|
5月前
|
存储 前端开发 JavaScript
在React中有效地管理组件之间的通信和数据流
在React中有效地管理组件之间的通信和数据流