π The Ultimate Solution for React Native Component Communication
A powerful and lightweight global event system designed specifically for React Native applications. Solve complex component communication issues, eliminate prop drilling, enable seamless cross-component function calls, and integrate perfectly with Redux/Saga workflows.
React Native developers face unique challenges:
- Deep Navigation Stacks: Components buried 5+ screens deep need to communicate with root components
- Redux/Saga Integration: Trigger component functions from Redux actions or Saga effects
- Cross-Screen Communication: Components on different screens need to interact
- Navigation Events: Handle navigation events across the entire app
- State Synchronization: Keep multiple components in sync with global state changes
- Background/Foreground Events: Handle app state changes across all components
- Push Notification Handling: Distribute notification events to relevant components
- Deep Linking: Route deep link events to appropriate components
- π― React Native Optimized: Built specifically for React Native performance and patterns
- π Redux/Saga Integration: Seamlessly trigger component functions from Redux actions
- π± Navigation Support: Perfect for React Navigation and deep navigation stacks
- β‘ Performance Optimized: Lightweight with minimal bundle impact
- π‘οΈ TypeScript Support: Full TypeScript support with comprehensive type definitions
- ποΈ Dual API: Class-based and Hook-based APIs for different use cases
- π§ Priority System: Execute listeners in priority order
- π¦ Scoped Events: Organize events with namespaces for better structure
- π§Ή Automatic Cleanup: Hooks automatically clean up listeners on unmount
β οΈ Error Handling: Graceful error handling with optional warnings
npm install react-native-global-event
yarn add react-native-global-event
Problem: You have Redux actions that need to trigger UI updates in specific components, but those components aren't connected to Redux.
// Redux Action
const loginUser = (userData) => ({
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 functions 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);
// Show success animation, update UI, etc.
});
useGlobalEventListener('redux-login-error', (error) => {
// Show error message, reset form, etc.
});
return user ? <Text>Welcome, {user.name}!</Text> : <Text>Please login</Text>;
}
Problem: A component deep in your navigation stack needs to communicate with a component on the root screen.
// Deep nested component (5+ screens deep)
function DeepNestedComponent() {
const { emit } = useGlobalEvent();
const handleUserAction = (action) => {
// π Communicate with root component without prop drilling
emit('user-action', { action, timestamp: Date.now() });
};
return (
<TouchableOpacity onPress={() => handleUserAction('profile-updated')}>
<Text>Update Profile</Text>
</TouchableOpacity>
);
}
// Root component that listens to deep events
function RootComponent() {
const [notifications, setNotifications] = useState([]);
useGlobalEventListener('user-action', (data) => {
setNotifications(prev => [...prev, data]);
// Show toast, update badge, etc.
});
return (
<View>
<Text>Notifications: {notifications.length}</Text>
{/* Your app content */}
</View>
);
}
Problem: Components on different screens need to communicate with each other.
// Screen A - Product List
function ProductListScreen() {
const { emit } = useGlobalEvent();
const addToCart = (product) => {
// π Notify cart screen about new item
emit('product-added-to-cart', product);
};
return (
<FlatList
data={products}
renderItem={({ item }) => (
<TouchableOpacity onPress={() => addToCart(item)}>
<Text>Add {item.name} to Cart</Text>
</TouchableOpacity>
)}
/>
);
}
// Screen B - Cart Screen
function CartScreen() {
const [cartItems, setCartItems] = useState([]);
useGlobalEventListener('product-added-to-cart', (product) => {
setCartItems(prev => [...prev, product]);
// Show success animation, update badge, etc.
});
return (
<View>
<Text>Cart Items: {cartItems.length}</Text>
{/* Cart content */}
</View>
);
}
Problem: You need to handle navigation events from anywhere in your app.
// Navigation service
class NavigationService {
static navigate(screenName, params) {
// Your navigation logic
globalEvent.emit('navigation-requested', { screenName, params });
}
}
// Component that handles navigation
function NavigationHandler() {
useGlobalEventListener('navigation-requested', ({ screenName, params }) => {
// Handle navigation logic
navigation.navigate(screenName, params);
});
return null; // This is a service component
}
// Any component can trigger navigation
function AnyComponent() {
const { emit } = useGlobalEvent();
const goToProfile = () => {
emit('navigation-requested', { screenName: 'Profile', params: { userId: 123 } });
};
return (
<TouchableOpacity onPress={goToProfile}>
<Text>Go to Profile</Text>
</TouchableOpacity>
);
}
Problem: Handle app state changes across all components.
// App state handler
function AppStateHandler() {
useEffect(() => {
const handleAppStateChange = (nextAppState) => {
globalEvent.emit('app-state-changed', { state: nextAppState });
};
const subscription = AppState.addEventListener('change', handleAppStateChange);
return () => subscription?.remove();
}, []);
return null;
}
// Components that react to app state changes
function DataSyncComponent() {
useGlobalEventListener('app-state-changed', ({ state }) => {
if (state === 'active') {
// Sync data when app becomes active
syncData();
}
});
return <Text>Data Sync Component</Text>;
}
Problem: Handle push notifications and distribute them to relevant components.
// Push notification handler
function PushNotificationHandler() {
useEffect(() => {
const handleNotification = (notification) => {
globalEvent.emit('push-notification-received', notification);
};
// Your push notification setup
return () => {
// Cleanup
};
}, []);
return null;
}
// Components that handle specific notifications
function ChatComponent() {
useGlobalEventListener('push-notification-received', (notification) => {
if (notification.type === 'chat') {
// Handle chat notification
updateChatList(notification.data);
}
});
return <Text>Chat Component</Text>;
}
Problem: Handle deep links and route them to appropriate components.
// Deep link handler
function DeepLinkHandler() {
useEffect(() => {
const handleDeepLink = (url) => {
globalEvent.emit('deep-link-received', { url });
};
// Your deep link setup
return () => {
// Cleanup
};
}, []);
return null;
}
// Components that handle deep links
function ProductDetailComponent() {
useGlobalEventListener('deep-link-received', ({ url }) => {
if (url.includes('/product/')) {
const productId = extractProductId(url);
// Navigate to product detail
navigateToProduct(productId);
}
});
return <Text>Product Detail Component</Text>;
}
Problem: Multiple components need to perform the same action simultaneously.
// Component A - User Profile
function UserProfile() {
const [user, setUser] = useState(null);
useGlobalEventListener('user-data-updated', (userData) => {
setUser(userData);
// Update profile UI
});
return <Text>Profile: {user?.name}</Text>;
}
// Component B - User Settings
function UserSettings() {
const [user, setUser] = useState(null);
useGlobalEventListener('user-data-updated', (userData) => {
setUser(userData);
// Update settings UI
});
return <Text>Settings for: {user?.name}</Text>;
}
// Component C - User Dashboard
function UserDashboard() {
const [user, setUser] = useState(null);
useGlobalEventListener('user-data-updated', (userData) => {
setUser(userData);
// Update dashboard UI
});
return <Text>Dashboard for: {user?.name}</Text>;
}
// Trigger update from anywhere
function UpdateUserButton() {
const { emit } = useGlobalEvent();
const updateUser = () => {
const newUserData = { name: 'John Doe', email: 'john@example.com' };
// π All three components will update simultaneously
emit('user-data-updated', newUserData);
};
return (
<TouchableOpacity onPress={updateUser}>
<Text>Update User</Text>
</TouchableOpacity>
);
}
import { globalEvent } from 'react-native-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();
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { useGlobalEvent, useGlobalEventListener } from 'react-native-global-event';
function MyComponent() {
const { emit } = useGlobalEvent();
useGlobalEventListener('data-loaded', (data) => {
console.log('Data received:', data);
});
const handlePress = () => {
emit('button-pressed', { timestamp: Date.now() });
};
return (
<TouchableOpacity onPress={handlePress}>
<Text>Press Me</Text>
</TouchableOpacity>
);
}
The main class for managing global events.
import { GlobalEvent } from 'react-native-global-event';
const globalEvent = new GlobalEvent();
Methods:
emit<T>(eventName: string, data?: T): void
- Emit an eventon<T>(eventName: string, listener: EventListener<T>, options?: { once?: boolean; priority?: number }): EventSubscription
- Register a listeneroff<T>(eventName: string, listener?: EventListener<T> | string): void
- Remove a listeneronce<T>(eventName: string, listener: EventListener<T>): EventSubscription
- Register a one-time listenerremoveAllListeners(eventName?: string): void
- Remove all listenersgetListenerCount(eventName: string): number
- Get listener countgetEventNames(): string[]
- Get all event namesscope(namespace: string): ScopedGlobalEvent
- Create a scoped event managerbatchEmit(events: Array<{ name: string; data?: any }>): void
- Emit multiple events
Namespace-aware event manager for better organization.
const userEvents = globalEvent.scope('user');
userEvents.emit('login', userData); // Actually emits 'user:login'
Main hook for event management with automatic cleanup.
const { emit, on, off, once, removeAllListeners, getListenerCount, getEventNames } = useGlobalEvent();
Hook for listening to a specific event with automatic cleanup.
useGlobalEventListener('user-login', (userData) => {
console.log('User logged in:', userData);
}, [dependency]);
Hook for one-time event listening.
useGlobalEventOnce('initial-data-loaded', (data) => {
console.log('Initial data loaded:', data);
});
Hook for scoped event management.
const userEvents = useScopedGlobalEvent('user');
userEvents.emit('login', userData);
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'
);
import { EventManager } from 'react-native-global-event';
const eventManager = EventManager.getInstance({
maxListeners: 50, // Maximum listeners per event
enableWarnings: true // Enable console warnings
});
// 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 });
The library includes comprehensive unit tests. Run tests with:
npm test
npm run test:coverage
- 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
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
- Built specifically for React Native developers
- Inspired by the need to solve complex component communication in React Native applications
- Comprehensive testing ensures reliability
- Made with β€οΈ for the React Native community
π Made with β€οΈ for React Native developers