Event Module
Decoupled communication between modules using events.
What Is EventModule?
EventModule allows modules to listen to events and respond to them automatically. It manages event listeners' lifecycle and provides context for navigation.
Quick Start
1. Create Event Module
class MyEventModule extends EventModule {
@override
void listen() {
on<UserLoggedInEvent>((event, context) {
if (context != null) {
context.go('/home');
}
});
}
@override
List<ModularRoute> get routes => [
ChildRoute('/', child: (_, __) => MyPage()),
];
}2. Send Events
class MyPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
// Send event
ModularEvent.fire(UserLoggedInEvent(userId: '123'));
},
child: Text('Login'),
);
}
}3. Listen to Events
The listen() method automatically registers listeners when the module is initialized:
class AuthModule extends EventModule {
@override
void listen() {
on<UserLoggedInEvent>((event, context) {
print('User ${event.userId} logged in!');
if (context != null) {
context.go('/dashboard');
}
});
}
}Event Types
Regular Events
Multiple modules can listen to the same event:
@override
void listen() {
on<DataUpdatedEvent>((event, context) {
print('Data: ${event.data}');
});
}
// Fire event
ModularEvent.fire(DataUpdatedEvent(data: 'new data'));Exclusive Events
Only one module receives the event at a time (FIFO queue):
@override
void listen() {
on<ImportantEvent>((event, context) {
print('Handled: ${event.message}');
}, exclusive: true);
}
// Fire event
ModularEvent.fire(ImportantEvent(message: 'urgent'));Real Example
// Event classes
class UserLoggedInEvent {
final String userId;
UserLoggedInEvent({required this.userId});
}
class ShowSnackBarEvent {
final String message;
ShowSnackBarEvent({required this.message});
}
// Auth module listens for login
class AuthModule extends EventModule {
@override
void listen() {
on<UserLoggedInEvent>((event, context) {
print('User ${event.userId} logged in!');
if (context != null) {
context.go('/dashboard');
}
});
}
@override
List<ModularRoute> get routes => [
ChildRoute('/login', child: (_, __) => LoginPage()),
];
}
// UI module listens for snackbar events
class UIModule extends EventModule {
@override
void listen() {
on<ShowSnackBarEvent>((event, context) {
if (context != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(event.message))
);
}
});
}
}
// Login page sends events
class LoginPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
ModularEvent.fire(UserLoggedInEvent(userId: '123'));
ModularEvent.fire(ShowSnackBarEvent(message: 'Welcome!'));
},
child: Text('Login'),
);
}
}Key Features
- Automatic lifecycle - Listeners are registered/disposed automatically
- Context injection - Navigation context provided automatically
- Exclusive events - FIFO queue system for critical events
- Memory management - No memory leaks, automatic cleanup
Best Practices
- Check context null - Always verify
context != nullbefore using - Use descriptive event names -
UserLoggedInEventnotEvent1 - Keep events simple - Just data, no business logic
- Use exclusive sparingly - Only for critical operations
- Test event flow - Ensure events reach their destinations
When to Use
✅ Good for:
- User authentication changes
- Cross-module notifications
- Navigation triggers
- UI updates from business logic
❌ Avoid for:
- Simple parent-child communication
- Direct data passing
- Frequent, high-volume events