React中是否存在类似Laravel的事件分发与监听机制?
React生态中的自定义事件分发与监听方案
你正在学习Laravel框架,觉得它的事件分发与监听实现很有趣,之前用过Electron的类似系统但体验不如Laravel,想知道React生态里有没有等价的机制——不是监听DOM事件的addEventListener,而是像你给出的Laravel示例那样,实现组件间的自定义事件通信:
Laravel示例代码:
// 订阅事件:在Feed组件中 #[On('tweet-created')] public function fetchTweets() { $this->tweets = Tweet::with('user') ->latest() ->get(); }
// 分发事件:在CreateTweet组件中,当新推文创建时触发 $this->dispatch('tweet-created');
下面是React生态中对应的几种实现方式:
一、React内置方案(无需第三方依赖)
可以通过Context + 自定义逻辑封装一个轻量的事件总线,实现跨组件的事件订阅与分发:
1. 创建事件总线Context
// EventBusContext.jsx import { createContext, useContext, useReducer, useCallback } from 'react'; const EventBusContext = createContext(); // 事件处理的reducer const eventReducer = (state, action) => { switch (action.type) { case 'SUBSCRIBE': return { ...state, [action.eventName]: [...(state[action.eventName] || []), action.callback] }; case 'UNSUBSCRIBE': return { ...state, [action.eventName]: (state[action.eventName] || []).filter(cb => cb !== action.callback) }; case 'EMIT': (state[action.eventName] || []).forEach(cb => cb(action.payload)); return state; default: return state; } }; export const EventBusProvider = ({ children }) => { const [state, dispatch] = useReducer(eventReducer, {}); // 订阅事件 const subscribe = useCallback((eventName, callback) => { dispatch({ type: 'SUBSCRIBE', eventName, callback }); // 返回取消订阅的函数 return () => dispatch({ type: 'UNSUBSCRIBE', eventName, callback }); }, [dispatch]); // 分发事件 const emit = useCallback((eventName, payload) => { dispatch({ type: 'EMIT', eventName, payload }); }, [dispatch]); return ( <EventBusContext.Provider value={{ subscribe, emit }}> {children} </EventBusContext.Provider> ); }; // 自定义Hook,方便组件使用 export const useEventBus = () => useContext(EventBusContext);
2. 在组件中使用
// Feed组件:订阅事件 import { useEffect } from 'react'; import { useEventBus } from './EventBusContext'; function Feed() { const { subscribe } = useEventBus(); useEffect(() => { // 订阅`tweet-created`事件,对应Laravel的#[On('tweet-created')] const unsubscribe = subscribe('tweet-created', () => { fetchTweets(); // 这里执行你的拉取推文逻辑 }); // 组件卸载时取消订阅,避免内存泄漏 return unsubscribe; }, [subscribe]); const fetchTweets = async () => { // 模拟Laravel中的Tweet查询逻辑 const res = await fetch('/api/tweets/latest'); const tweets = await res.json(); // 更新组件内的tweets状态 // setTweets(tweets); }; return <div> {/* 渲染推文列表 */} </div>; }
// CreateTweet组件:分发事件 import { useEventBus } from './EventBusContext'; function CreateTweet() { const { emit } = useEventBus(); const handleSubmit = async () => { // 模拟创建推文的API请求 await fetch('/api/tweets', { method: 'POST', body: /* 推文数据 */ }); // 分发`tweet-created`事件,对应Laravel的$this->dispatch('tweet-created') emit('tweet-created'); }; return <button onClick={handleSubmit}>发布推文</button>; }
二、第三方库方案
如果不想自己封装,轻量级的事件库可以快速实现需求:
1. 使用mitt
mitt是一个只有200B大小的事件发射器,用法简洁:
npm install mitt
// 创建全局事件总线实例 // eventBus.js import mitt from 'mitt'; export const eventBus = mitt();
// Feed组件中订阅事件 import { useEffect } from 'react'; import { eventBus } from './eventBus'; function Feed() { useEffect(() => { const handler = () => fetchTweets(); eventBus.on('tweet-created', handler); return () => eventBus.off('tweet-created', handler); }, []); const fetchTweets = async () => { /* 拉取推文逻辑 */ }; return <div> {/* 渲染列表 */} </div>; }
// CreateTweet组件中分发事件 import { eventBus } from './eventBus'; function CreateTweet() { const handleSubmit = async () => { await fetch('/api/tweets', { method: 'POST' }); eventBus.emit('tweet-created'); }; return <button onClick={handleSubmit}>发布推文</button>; }
2. 使用tiny-emitter
tiny-emitter也是轻量的事件库,API类似Node.js的EventEmitter:
npm install tiny-emitter
// eventBus.js import Emitter from 'tiny-emitter'; export const eventBus = new Emitter();
// Feed组件订阅 eventBus.on('tweet-created', () => fetchTweets()); // 取消订阅 eventBus.off('tweet-created', handler); // CreateTweet组件分发 eventBus.emit('tweet-created');
这些方案都能实现你需要的、类似Laravel的组件间自定义事件通信,不需要依赖DOM事件系统。
内容的提问来源于stack exchange,提问作者Yusuf Bouzekri
相关产品推荐
相关产品推荐

