In this lesson, you will learn how to use the Mediator pattern to decouple your UI components by routing event notifications through an in-memory message bus.
The Problem: Tight Coupling
In complex Blazor applications, components often need to talk to each other without having a direct parent-child relationship. You could pass events up through multiple layers of components using EventCallback, but this leads to "prop drilling," where intermediate components become cluttered with logic they don’t actually use.
The Solution: The Mediator Pattern
Instead of components talking to each other directly, they talk to a central "Mediator." A component can publish a message to the bus, and other components can subscribe to that bus to react whenever a specific event occurs. Because you already understand the Blazor DI Container (Concept 12), we can register a singleton service to act as our bus.
Implementation Illustration
First, define a simple service to handle the communication:
public class EventBus
{
public event Action<string>? OnNotificationReceived;
public void Notify(string message) => OnNotificationReceived?.Invoke(message);
}
Register this in your Program.cs as a singleton: builder.Services.AddSingleton<EventBus>();.
Now, any component can inject the EventBus to communicate:
The Publisher:
@inject EventBus Bus
<button @onclick="() => Bus.Notify('Update completed!')">Trigger Event</button>
The Subscriber:
@implements IDisposable
@inject EventBus Bus
<p>@message</p>
@code {
private string message = "Waiting...";
protected override void OnInitialized() => Bus.OnNotificationReceived += HandleNotification;
private void HandleNotification(string msg) {
message = msg;
InvokeAsync(StateHasChanged);
}
public void Dispose() => Bus.OnNotificationReceived -= HandleNotification;
}
By using this approach, the button doesn’t need to know who is listening, and the listener doesn’t need to know which component triggered the action. This keeps your components clean, modular, and focused solely on their own rendering logic.
Key Takeaway: The Mediator pattern replaces direct component dependencies with an event-driven bus, allowing disconnected parts of your UI to communicate seamlessly without knowing about each other’s existence.