State in Micro-Frontends
State Management Patterns for Micro Frontends¶
Micro frontends introduce complexity in state management due to the need for decoupling between independently developed, deployable units. Traditional global state management solutions (e.g., Redux, Context API) often lead to tight coupling or inconsistent state across boundaries. This section outlines patterns to decouple state management in micro frontend architectures using shared context and service layers, balancing isolation and collaboration.
## Shared Context Pattern¶
The shared context pattern uses a centralized state store or context that micro frontends can access while maintaining isolation. This approach leverages scoped state and event-driven communication to avoid direct coupling.
Key Concepts¶
- Central Context Provider: A shared context (e.g., React's
Context APIor a global state store) acts as a mediator for state access. - Scoped State: Each micro frontend manages its own state slice, but can subscribe to shared context events or state changes.
- Event-Driven Communication: Micro frontends emit events (e.g., via a message bus) to notify others of state changes, avoiding direct dependencies.
Example: React Context with Scoped State¶
// SharedContextProvider.js
import { createContext, useContext, useState } from 'react';
const SharedContext = createContext();
export const SharedContextProvider = ({ children }) => {
const [sharedState, setSharedState] = useState({ global: 'default' });
return (
<SharedContext.Provider value={{ sharedState, setSharedState }}>
{children}
</SharedContext.Provider>
);
};
export const useSharedContext = () => useContext(SharedContext);
// MicroFrontendA.jsx
import { useSharedContext } from './SharedContextProvider';
const MicroFrontendA = () => {
const { sharedState, setSharedState } = useSharedContext();
return (
<div>
<p>Shared State: {sharedState.global}</p>
<button onClick={() => setSharedState({ global: 'updated' })}>
Update Shared State
</button>
</div>
);
};
Diagram¶
[MicroFrontendA] --> [SharedContextProvider] --> [MicroFrontendB]
^ ^
| |
v |
[EventBus] <---> [SharedContext] |
^ |
| |
[MicroFrontendC] <---> [SharedContext]
Considerations¶
- Isolation: Avoid exposing raw state; use events or actions to trigger updates.
- Consistency: Ensure state updates are synchronized across micro frontends.
- Tooling: Use libraries like Redux Toolkit or Zustand for structured state management.
## Service Layer Pattern¶
The service layer pattern decouples state management by abstracting it into a central service. Micro frontends interact with this service via APIs (HTTP, WebSocket, or gRPC), enabling loose coupling and centralized control.
Key Concepts¶
- Central Service: A backend or API service manages shared state, acting as a single source of truth.
- API-Driven Communication: Micro frontends fetch or update state through the service, avoiding direct dependencies.
- Event Sourcing: State changes are recorded as events, which micro frontends can subscribe to for updates.
Example: REST API for Shared State¶
// SharedStateService.js
export const getSharedState = async () => {
const response = await fetch('/api/shared-state');
return response.json();
};
export const updateSharedState = async (payload) => {
const response = await fetch('/api/shared-state', {
method: 'POST',
body: JSON.stringify(payload),
});
return response.json();
};
// MicroFrontendA.jsx
import { updateSharedState } from './SharedStateService';
const MicroFrontendA = () => {
const handleUpdate = async () => {
await updateSharedState({ global: 'updated' });
};
return <button onClick={handleUpdate}>Update State</button>;
};
Diagram¶
[MicroFrontendA] --> [SharedStateService] --> [Database]
^ ^
| |
[MicroFrontendB] <-- [SharedStateService] |
^ |
[MicroFrontendC] <-- [SharedStateService] |
Considerations¶
- Latency: API calls may introduce latency; use caching or WebSockets for real-time updates.
- Security: Implement authentication and authorization to protect state access.
- Scalability: Use message queues (e.g., Kafka, RabbitMQ) for high-throughput state synchronization.
## Key Takeaways¶
- Shared Context: Use a centralized context provider with scoped state and event-driven communication for lightweight coupling.
- Service Layer: Abstract state management into a central service for API-driven, scalable decoupling.
- Balance Isolation and Collaboration: Prioritize scoped state and event buses to avoid tight coupling while enabling necessary state sharing.