Migration guide: v0.11.x → v0.12.0
This guide will help you migrate your codebase from use-less-react v0.11.x to v0.12.0. The main changes focus on improving the Developer Experience (DX) and type safety of the Event Bus.
Overview of Changes
The v0.12.0 release introduces significant improvements to the Event Bus:
- New
EventHandlerBuilderclass for fluent handler registration - Improved type inference in
registerLocalHandler - API simplification with removal of
unregisterLocalHandler
Breaking Changes
1.Improved Type Inference for registerLocalHandler
The type signature of registerLocalHandler has been improved to provide better developer experience.
Before (v0.11.x)
// specify type AND payload
bus.registerLocalHandler<"UserCreated", UserCreatedPayload>(
"UserCreated",
async (event: UserCreatedEvent) => {
console.log('User created:', event.payload.email);
}
);
After (v0.12.0)
Pass event class as generic type: type and payload are inferred:
const unsubscribe = bus.registerLocalHandler<UserCreatedEvent>(
"UserCreated",
async (event: UserCreatedEvent) => {
console.log('User created:', event.payload.email);
}
);
Or, if your handler function is explicitly typed:
const handler: LocalEventHandler<UserCreatedEvent> = async (event) => {
console.log('User created:', event.payload.email);
}
// no need to specify any generics
const unsubscribe = bus.registerLocalHandler(
"UserCreated",
handler
);
2. Removal of unregisterLocalHandler
The unregisterLocalHandler method has been removed from the Event Bus API.
Use the cleanup function returned by registerLocalHandler and by EventHandlerBuilder.build.
New Features
EventHandlerBuilder
The new EventHandlerBuilder class provides a fluent API for registering multiple event handlers. This is particularly useful when you need to register many handlers and want a centralized cleanup mechanism.
Quick Example
import { EventHandlerBuilder } from '@dxbox/use-less-react/classes';
const cleanup = new EventHandlerBuilder(bus)
.on<UserCreatedEvent>("UserCreated", handler1)
.on<UserCreatedEvent>("UserCreated", handler2)
.on<UserDeletedEvent>("UserDeleted", handler3)
.build();
// Cleanup all handlers at once
cleanup();
When to Use
✅ Recommended when:
- You need to register 2 or more handlers
- You want to group registrations logically
- You need centralized cleanup (e.g., in React useEffect)
❌ Not necessary when:
- Registering a single handler
- Handlers have different lifecycles
For more details, see the EventHandlerBuilder documentation.
Migration Checklist
Use this checklist to ensure a smooth migration:
-
Search for
unregisterLocalHandler: Find all occurrences in your codebase -
Update to unsubscribe pattern: Replace with the function returned by
registerLocalHandler -
Update
registerLocalHandlergenerics: Change from<TType, TPayload>to<EventClass>wherever the handler is not explicitly typed. Otherwise simply omit the generics. -
Consider using
EventHandlerBuilder: For multiple handler registrations -
Update tests: Ensure your tests reflect the new API
-
Update TypeScript types: If you have type definitions that reference the old API
-
Run type checker: Verify everything compiles
npm run type-check
# or
tsc --noEmit -
Run tests: Ensure all tests pass
npm test
Common Migration Patterns
Pattern 1: Simple Handler Registration
// Before (v0.11.x)
bus.registerLocalHandler<"UserCreated", UserCreatedPayload>(
"UserCreated",
async (event) => {
console.log(event.payload.email);
}
);
bus.unregisterLocalHandler("UserCreated", handler);
// After (v0.12.0)
const unsubscribe = bus.registerLocalHandler<UserCreatedEvent>(
"UserCreated",
async (event) => {
console.log(event.payload.email);
}
);
unsubscribe();
Pattern 2: Multiple Handlers in a Service
// Before (v0.11.x)
class UserService {
private handler1 = async (event: UserCreatedEvent) => { /* ... */ };
private handler2 = async (event: UserDeletedEvent) => { /* ... */ };
initialize() {
bus.registerLocalHandler<"UserCreated", UserCreatedPayload>(
"UserCreated",
this.handler1
);
bus.registerLocalHandler<"UserDeleted", UserDeletedPayload>(
"UserDeleted",
this.handler2
);
}
destroy() {
bus.unregisterLocalHandler("UserCreated", this.handler1);
bus.unregisterLocalHandler("UserDeleted", this.handler2);
}
}
// After (v0.12.0) - Option 1: Manual cleanup
class UserService {
private unsubscribers: Array<() => void> = [];
initialize() {
this.unsubscribers.push(
bus.registerLocalHandler<UserCreatedEvent>(
"UserCreated",
async (event) => { /* ... */ }
)
);
this.unsubscribers.push(
bus.registerLocalHandler<UserDeletedEvent>(
"UserDeleted",
async (event) => { /* ... */ }
)
);
}
destroy() {
this.unsubscribers.forEach(unsub => unsub());
this.unsubscribers = [];
}
}
// After (v0.12.0) - Option 2: Using EventHandlerBuilder (Recommended)
class UserService {
private cleanup?: () => void;
initialize() {
this.cleanup = new EventHandlerBuilder(bus)
.on<UserCreatedEvent>("UserCreated", async (event) => { /* ... */ })
.on<UserDeletedEvent>("UserDeleted", async (event) => { /* ... */ })
.build();
}
destroy() {
this.cleanup?.();
}
}
Need Help?
If you encounter issues during migration:
- Check the Event Bus documentation
- Open an issue on GitHub
Version Compatibility
- v0.12.0 and later: Use the new API as described in this guide
- v0.11.x and earlier: Use the old API with
unregisterLocalHandler - Mixed versions: Not recommended. Update all packages to v0.12.0 or later
Summary
The v0.12.0 migration primarily involves:
- ✅ Replacing
unregisterLocalHandlercalls with unsubscribe functions - ✅ Updating
registerLocalHandlergeneric parameters to use event classes - ✅ Optionally adopting
EventHandlerBuilderfor cleaner code
These changes result in:
- 🎯 Better type safety
- 🚀 Improved developer experience
- 📚 More maintainable code
- 💡 Better IDE support
Happy coding! 🎉