Middleware
Using middleware in Aurelia Store to intercept and transform state changes
Middleware act as an intermediary step in your application to allow you to intercept, modify, or block state changes. They run either before or after your action handlers execute, giving you powerful control over state transitions.
How Middleware Works
Middleware functions receive:
The current state
The dispatched action
Optional settings you provide during registration
They can:
Transform state by returning a new state object
Block actions by returning
falsePass through by returning
undefinedor nothingRun asynchronously by returning a Promise
Creating Middleware
A middleware function has the following signature:
import { IStateMiddleware } from '@aurelia/state';
// Basic middleware (no settings)
const loggingMiddleware: IStateMiddleware<MyState> = (state, action, settings) => {
console.log('Action dispatched:', action);
console.log('Current state:', state);
// Return undefined to pass through without changes
};
// Middleware with settings
interface ValidationSettings {
strict: boolean;
}
const validationMiddleware: IStateMiddleware<MyState, ValidationSettings> = (state, action, settings) => {
if (settings.strict && !isValidAction(action)) {
return false; // Block the action
}
// Pass through
};Registering Middleware
Use registerMiddleware() on the store to add middleware. Specify whether it should run 'before' or 'after' action handlers:
Common Middleware Patterns
Logging Middleware
Validation Middleware
Transform Middleware
Async Middleware
Analytics Middleware
Middleware Execution Order
When multiple middleware are registered for the same placement, they execute in registration order:
Each middleware receives the state returned by the previous middleware:
Blocking Actions
Returning false from middleware prevents the action from completing:
Before middleware returns
false: Action handlers don't run, state isn't updatedAfter middleware returns
false: State changes from handlers are discarded
Type Safety
Use TypeScript generics for type-safe middleware:
Best Practices
Keep middleware focused — Each middleware should have a single responsibility
Avoid side effects in 'before' middleware — Save side effects (API calls, logging) for 'after' middleware when possible
Clean up middleware — Unregister middleware when components are destroyed to prevent memory leaks
Handle errors gracefully — Errors in middleware are caught and logged, but the state passes through unchanged
Use settings for configuration — Pass configuration via settings rather than closures for better testability
Consider async implications — Async middleware can delay state updates; use sparingly for time-sensitive operations
Last updated
Was this helpful?