用 zustand 实现简单的事件分发中心

需求

实现一个轻量级的事件分发中心,不影响现有的框架和数据结构。

实现

准备用zustand这个状态管理库来做。

安装

首先,安装zustand库:

bash

npm install zustand

创建一个事件分发中心

然后,创建一个事件分发中心,如eventCenter.js

javascript

import create from 'zustand';

const useEventCenter = create((set, get) => ({
  events: new Map(),

  on: (eventName, callback) => {
    const { events } = get();

    if (!events.has(eventName)) {
      events.set(eventName, []);
    }

    events.get(eventName).push(callback);
    set({ events });
  },

  off: (eventName, callback) => {
    const { events } = get();

    if (events.has(eventName)) {
      const filteredCallbacks = events.get(eventName).filter(cb => cb !== callback);
      events.set(eventName, filteredCallbacks);
      set({ events });
    }
  },

  emit: (eventName, ...args) => {
    const { events } = get();

    if (events.has(eventName)) {
      events.get(eventName).forEach(callback => callback(...args));
    }
  },
}));

export default useEventCenter;

使用zustand创建了一个存储,包含events(用于存储事件回调的Map对象)以及三个方法:on(用于订阅事件)、off(用于取消订阅事件)和emit(用于触发事件)。

在组件中使用useEventCenter进行事件订阅和触发。例如,以下是一个简单的ParentChild组件示例:

Parent.js:

javascript

import React, { useEffect } from 'react';
import useEventCenter from './eventCenter';
import Child from './Child';

const Parent = () => {
  const { on, off, emit } = useEventCenter();

  useEffect(() => {
    const handleButtonClick = () => {
      console.log('Button clicked in Child component');
    };

    on('buttonClick', handleButtonClick);

    return () => {
      off('buttonClick', handleButtonClick);
    };
  }, [on, off]);

  return (
    <div>
      <h1>Parent Component</h1>
      <Child onButtonClick={() => emit('buttonClick')} />
    </div>
  );
};

export default Parent;

Child.js:

javascript

import React from 'react';

const Child = ({ onButtonClick }) => {
  return (
    <div>
      <h2>Child Component</h2>
      <button onClick={onButtonClick}>Click me</button>
    </div>
  );
};

export default Child;

多个组件之间的事件通信。

首先,创建一个新的组件Sibling.js,它将与Child.js并列:

Sibling.js:

javascript

import React, { useEffect } from 'react';
import useEventCenter from './eventCenter';

const Sibling = () => {
  const { on, off } = useEventCenter();

  useEffect(() => {
    const handleButtonClick = () => {
      console.log('Button clicked in Sibling component');
    };

    on('buttonClick', handleButtonClick);

    return () => {
      off('buttonClick', handleButtonClick);
    };
  }, [on, off]);

  return (
    <div>
      <h2>Sibling Component</h2>
    </div>
  );
};

export default Sibling;

Sibling.js组件中,订阅了名为buttonClick的事件,以便在Child.js组件中触发该事件时收到通知。

现在,需要更新Parent.js组件以包含Sibling.js组件:

Parent.js:

javascript

import React from 'react';
import Child from './Child';
import Sibling from './Sibling';

const Parent = () => {
  return (
    <div>
      <h1>Parent Component</h1>
      <Child />
      <Sibling />
    </div>
  );
};

export default Parent;

参考资料

zustand