Skip to content

t-code4change/react-global-event

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

React Global Event

A powerful and lightweight global event system for React and React Native applications. Solve complex component communication issues, eliminate prop drilling, and enable seamless cross-component function calls with ease.

πŸš€ Features

  • Universal Compatibility: Works with both React and React Native
  • Dual API: Class-based and Hook-based APIs for different use cases
  • TypeScript Support: Full TypeScript support with comprehensive type definitions
  • Priority System: Execute listeners in priority order
  • Scoped Events: Organize events with namespaces
  • Automatic Cleanup: Hooks automatically clean up listeners on unmount
  • Error Handling: Graceful error handling with optional warnings
  • Performance Optimized: Lightweight and efficient event management
  • Comprehensive Testing: 100% test coverage with Jest

πŸ“¦ Installation

npm install react-global-event
yarn add react-global-event

🎯 Problem Solving

This library solves common React/React Native communication challenges:

  • Prop Drilling: Eliminate the need to pass callbacks through multiple component levels
  • Child-to-Parent Communication: Allow deeply nested components to communicate with parents
  • Cross-Component Function Calls: Call functions in any component from anywhere in your app
  • Redux/Saga Integration: Trigger component functions from Redux actions or Saga effects
  • Module Communication: Enable communication between different modules or features

πŸš€ Quick Start

Basic Usage

import { globalEvent } from 'react-global-event';

// Emit an event
globalEvent.emit('user-login', { userId: 123, username: 'john' });

// Listen to an event
const subscription = globalEvent.on('user-login', (userData) => {
  console.log('User logged in:', userData);
});

// Clean up
subscription.remove();

React Hook Usage

import React from 'react';
import { useGlobalEvent, useGlobalEventListener } from 'react-global-event';

function MyComponent() {
  const { emit } = useGlobalEvent();

  useGlobalEventListener('data-loaded', (data) => {
    console.log('Data received:', data);
  });

  const handleClick = () => {
    emit('button-clicked', { timestamp: Date.now() });
  };

  return <button onClick={handleClick}>Click Me</button>;
}

πŸ“š API Reference

Class-based API

GlobalEvent

The main class for managing global events.

import { GlobalEvent } from 'react-global-event';

const globalEvent = new GlobalEvent();

Methods:

  • emit<T>(eventName: string, data?: T): void - Emit an event
  • on<T>(eventName: string, listener: EventListener<T>, options?: { once?: boolean; priority?: number }): EventSubscription - Register a listener
  • off<T>(eventName: string, listener?: EventListener<T> | string): void - Remove a listener
  • once<T>(eventName: string, listener: EventListener<T>): EventSubscription - Register a one-time listener
  • removeAllListeners(eventName?: string): void - Remove all listeners
  • getListenerCount(eventName: string): number - Get listener count
  • getEventNames(): string[] - Get all event names
  • scope(namespace: string): ScopedGlobalEvent - Create a scoped event manager
  • batchEmit(events: Array<{ name: string; data?: any }>): void - Emit multiple events

ScopedGlobalEvent

Namespace-aware event manager for better organization.

const userEvents = globalEvent.scope('user');
userEvents.emit('login', userData); // Actually emits 'user:login'

Hook-based API

useGlobalEvent

Main hook for event management with automatic cleanup.

const { emit, on, off, once, removeAllListeners, getListenerCount, getEventNames } = useGlobalEvent();

useGlobalEventListener

Hook for listening to a specific event with automatic cleanup.

useGlobalEventListener('user-login', (userData) => {
  console.log('User logged in:', userData);
}, [dependency]);

useGlobalEventOnce

Hook for one-time event listening.

useGlobalEventOnce('initial-data-loaded', (data) => {
  console.log('Initial data loaded:', data);
});

useScopedGlobalEvent

Hook for scoped event management.

const userEvents = useScopedGlobalEvent('user');
userEvents.emit('login', userData);

useGlobalEventState

Hook for managing component state based on events.

const [userData, setUserData] = useGlobalEventState('user-updated', null);
const [isOnline, setIsOnline] = useGlobalEventState(
  'connection-status',
  false,
  (data) => data.status === 'connected'
);

πŸ’‘ Use Cases & Examples

1. Solving Prop Drilling

Problem: Passing callbacks through multiple component levels

// ❌ Before: Prop drilling
function App() {
  const handleUserAction = (action) => {
    console.log('User action:', action);
  };

  return <Parent onUserAction={handleUserAction} />;
}

function Parent({ onUserAction }) {
  return <Child onUserAction={onUserAction} />;
}

function Child({ onUserAction }) {
  return <DeepChild onUserAction={onUserAction} />;
}

function DeepChild({ onUserAction }) {
  return <button onClick={() => onUserAction('clicked')}>Click</button>;
}

// βœ… After: Global events
function App() {
  useGlobalEventListener('user-action', (action) => {
    console.log('User action:', action);
  });

  return <Parent />;
}

function DeepChild() {
  const { emit } = useGlobalEvent();
  
  return (
    <button onClick={() => emit('user-action', 'clicked')}>
      Click
    </button>
  );
}

2. Cross-Component Function Calls

Problem: Calling functions in one component from another

// Component A - Has data that others need
function ComponentA() {
  const [data, setData] = useState('Initial data');

  useGlobalEventListener('get-data', () => {
    globalEvent.emit('data-response', { data });
  });

  useGlobalEventListener('update-data', (newData) => {
    setData(newData);
  });

  return <div>Data: {data}</div>;
}

// Component B - Needs data from Component A
function ComponentB() {
  const [receivedData, setReceivedData] = useState('');

  useGlobalEventListener('data-response', (response) => {
    setReceivedData(response.data);
  });

  const getData = () => {
    globalEvent.emit('get-data');
  };

  const updateData = () => {
    globalEvent.emit('update-data', 'Updated by Component B');
  };

  return (
    <div>
      <p>Data from A: {receivedData}</p>
      <button onClick={getData}>Get Data</button>
      <button onClick={updateData}>Update Data</button>
    </div>
  );
}

3. Redux/Saga Integration

Problem: Triggering component functions from Redux actions or Saga effects

// Redux Action
const loginUser = (userData) => {
  return {
    type: 'LOGIN_USER',
    payload: userData
  };
};

// Saga Effect
function* loginUserSaga(action) {
  try {
    const userData = yield call(api.login, action.payload);
    yield put({ type: 'LOGIN_SUCCESS', payload: userData });
    
    // Trigger component function via global event
    globalEvent.emit('redux-user-login', userData);
  } catch (error) {
    globalEvent.emit('redux-login-error', error);
  }
}

// Component that reacts to Redux events
function UserProfile() {
  const [user, setUser] = useState(null);

  useGlobalEventListener('redux-user-login', (userData) => {
    setUser(userData);
  });

  useGlobalEventListener('redux-login-error', (error) => {
    console.error('Login failed:', error);
  });

  return user ? <div>Welcome, {user.name}!</div> : <div>Please login</div>;
}

4. Module Communication

Problem: Communication between different modules or features

// User Module
function UserModule() {
  const userEvents = useScopedGlobalEvent('user');

  const updateProfile = (profileData) => {
    // Update profile logic
    userEvents.emit('profile-updated', profileData);
  };

  return <button onClick={() => updateProfile({ name: 'John' })}>Update Profile</button>;
}

// Notification Module
function NotificationModule() {
  useGlobalEventListener('user:profile-updated', (profileData) => {
    showNotification(`Profile updated: ${profileData.name}`);
  });

  return <div>Notifications</div>;
}

5. Event State Management

Problem: Keeping component state in sync with global events

function ConnectionStatus() {
  const [isOnline, setIsOnline] = useGlobalEventState(
    'connection-status',
    false,
    (data) => data.status === 'connected'
  );

  const [userCount, setUserCount] = useGlobalEventState('user-count', 0);

  return (
    <div>
      <p>Status: {isOnline ? 'Online' : 'Offline'}</p>
      <p>Users: {userCount}</p>
    </div>
  );
}

πŸ”§ Configuration

EventManager Options

import { EventManager } from 'react-global-event';

const eventManager = EventManager.getInstance({
  maxListeners: 50,        // Maximum listeners per event
  enableWarnings: true     // Enable console warnings
});

Priority System

// Higher priority listeners execute first
globalEvent.on('data-loaded', highPriorityHandler, { priority: 10 });
globalEvent.on('data-loaded', normalHandler, { priority: 5 });
globalEvent.on('data-loaded', lowPriorityHandler, { priority: 1 });

πŸ§ͺ Testing

The library includes comprehensive unit tests. Run tests with:

npm test
npm run test:coverage

πŸ“Š Performance

  • Lightweight: Minimal bundle size impact
  • Efficient: Optimized event handling and cleanup
  • Memory Safe: Automatic cleanup prevents memory leaks
  • Type Safe: Full TypeScript support for better development experience

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgments

  • Inspired by the need to solve complex component communication in React applications
  • Built with TypeScript for better developer experience
  • Comprehensive testing ensures reliability

Made with ❀️ for the React community

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published