Design enterprise-grade state architectures for large-scale applications with scalability, maintainability, and advanced patterns
Design enterprise-grade state architectures for large-scale applications with scalability, maintainability, and advanced patterns
Welcome to the final lesson in our React State Management course! This comprehensive guide covers enterprise-grade state architecture patterns, scalability strategies, and production deployment considerations for large-scale applications.
By the end of this lesson, you'll be able to:
Organize your state management around business domains:
1// Domain-based state structure
2interface AppState {
3 // User Management Domain
4 userManagement: {
5 users: UsersState;
6 authentication: AuthState;
7 permissions: PermissionsState;
8 };
9
10 // Content Management Domain
11 contentManagement: {
12 articles: ArticlesState;
13 media: MediaState;
14 comments: CommentsState;
15 };
16
17 // Analytics Domain
18 analytics: {
19 events: EventsState;
20 metrics: MetricsState;
21 reports: ReportsState;
22 };
23
24 // Infrastructure
25 infrastructure: {
26 cache: CacheState;
27 notifications: NotificationsState;
28 errors: ErrorState;
29 };
30}
31
32// Domain-specific store modules
33const createUserManagementStore = () => ({
34 users: usersSlice.reducer,
35 authentication: authSlice.reducer,
36 permissions: permissionsSlice.reducer
37});
38
39const createContentManagementStore = () => ({
40 articles: articlesSlice.reducer,
41 media: mediaSlice.reducer,
42 comments: commentsSlice.reducer
43});1// Presentation Layer
2interface PresentationLayer {
3 ui: UIState;
4 routing: RoutingState;
5 theming: ThemingState;
6}
7
8// Business Logic Layer
9interface BusinessLayer {
10 workflows: WorkflowsState;
11 validation: ValidationState;
12 calculations: CalculationsState;
13}
14
15// Data Access Layer
16interface DataLayer {
17 entities: EntitiesState;
18 cache: CacheState;
19 sync: SyncState;
20}
21
22// Infrastructure Layer
23interface InfrastructureLayer {
24 api: ApiState;
25 monitoring: MonitoringState;
26 configuration: ConfigState;
27}1// Host application store
2const createHostStore = () => {
3 return configureStore({
4 reducer: {
5 // Shared state
6 shared: sharedReducer,
7 auth: authReducer,
8
9 // Module federation containers
10 modules: modulesReducer
11 },
12 middleware: (getDefaultMiddleware) =>
13 getDefaultMiddleware()
14 .concat(moduleRegistrationMiddleware)
15 .concat(crossModuleCommunicationMiddleware),
16
17 enhancers: [
18 // Enable cross-module state sharing
19 crossModuleStateEnhancer,
20 // Module lifecycle management
21 moduleLifecycleEnhancer
22 ]
23 });
24};
25
26// Micro-frontend module registration
27const registerMicroFrontend = (
28 moduleName: string,
29 moduleStore: any,
30 stateShape: any
31) => {
32 return {
33 type: 'REGISTER_MODULE',
34 payload: {
35 moduleName,
36 reducer: moduleStore.reducer,
37 middleware: moduleStore.middleware,
38 stateShape
39 }
40 };
41};1// Event bus for cross-module communication
2class ModuleCommunicationBus {
3 private subscribers: Map<string, Function[]> = new Map();
4
5 subscribe(eventType: string, handler: Function) {
6 if (!this.subscribers.has(eventType)) {
7 this.subscribers.set(eventType, []);
8 }
9 this.subscribers.get(eventType)!.push(handler);
10 }
11
12 publish(eventType: string, payload: any) {
13 const handlers = this.subscribers.get(eventType) || [];
14 handlers.forEach(handler => handler(payload));
15 }
16
17 // Redux integration
18 createMiddleware(): Middleware {
19 return (store) => (next) => (action) => {
20 const result = next(action);
21
22 if (action.type.startsWith('@@CROSS_MODULE/')) {
23 this.publish(action.type, {
24 action,
25 state: store.getState()
26 });
27 }
28
29 return result;
30 };
31 }
32}
33
34// Module A publishes an event
35dispatch({
36 type: '@@CROSS_MODULE/USER_PROFILE_UPDATED',
37 payload: { userId: '123', profile: updatedProfile }
38});
39
40// Module B listens for the event
41communicationBus.subscribe(
42 '@@CROSS_MODULE/USER_PROFILE_UPDATED',
43 ({ action, state }) => {
44 // Update local state based on user profile change
45 dispatch(syncUserProfile(action.payload));
46 }
47);1// Complex entity relationships
2interface NormalizedState {
3 entities: {
4 users: { [id: string]: User };
5 articles: { [id: string]: Article };
6 comments: { [id: string]: Comment };
7 tags: { [id: string]: Tag };
8 categories: { [id: string]: Category };
9 };
10
11 relationships: {
12 userArticles: { [userId: string]: string[] };
13 articleComments: { [articleId: string]: string[] };
14 articleTags: { [articleId: string]: string[] };
15 categoryArticles: { [categoryId: string]: string[] };
16 };
17
18 indexes: {
19 articlesByDate: string[];
20 articlesByPopularity: string[];
21 usersByRole: { [role: string]: string[] };
22 };
23}
24
25// Entity normalization utility
26class EntityNormalizer {
27 static normalize<T extends { id: string }>(
28 entities: T[],
29 relationships: RelationshipMap = {}
30 ): NormalizedEntityState<T> {
31 const byId: { [id: string]: T } = {};
32 const allIds: string[] = [];
33
34 entities.forEach(entity => {
35 byId[entity.id] = entity;
36 allIds.push(entity.id);
37 });
38
39 return {
40 byId,
41 allIds,
42 relationships: this.buildRelationships(entities, relationships),
43 indexes: this.buildIndexes(entities)
44 };
45 }
46
47 static denormalize<T>(
48 ids: string[],
49 entities: { [id: string]: T },
50 relationships: RelationshipMap = {}
51 ): T[] {
52 return ids
53 .map(id => entities[id])
54 .filter(Boolean)
55 .map(entity => this.attachRelationships(entity, relationships));
56 }
57}1// Multi-level caching system
2interface CacheState {
3 memory: {
4 hot: { [key: string]: any }; // Most frequently accessed
5 warm: { [key: string]: any }; // Recently accessed
6 cold: { [key: string]: any }; // Least recently used
7 };
8
9 persistence: {
10 localStorage: { [key: string]: any };
11 indexedDB: { [key: string]: any };
12 sessionStorage: { [key: string]: any };
13 };
14
15 network: {
16 etags: { [url: string]: string };
17 lastModified: { [url: string]: string };
18 staleWhileRevalidate: { [key: string]: any };
19 };
20
21 policies: {
22 ttl: { [key: string]: number };
23 invalidation: { [pattern: string]: string[] };
24 compression: { [key: string]: boolean };
25 };
26}
27
28// Cache management slice
29const cacheSlice = createSlice({
30 name: 'cache',
31 initialState: createInitialCacheState(),
32 reducers: {
33 cacheData: (state, action: PayloadAction<{
34 key: string;
35 data: any;
36 ttl?: number;
37 level: 'hot' | 'warm' | 'cold';
38 }>) => {
39 const { key, data, ttl, level } = action.payload;
40
41 // Store in memory cache
42 state.memory[level][key] = data;
43
44 // Set TTL if provided
45 if (ttl) {
46 state.policies.ttl[key] = Date.now() + ttl;
47 }
48
49 // Promote to hot cache if accessed frequently
50 if (level !== 'hot' && this.isFrequentlyAccessed(key)) {
51 delete state.memory[level][key];
52 state.memory.hot[key] = data;
53 }
54 },
55
56 invalidateCache: (state, action: PayloadAction<string | string[]>) => {
57 const keys = Array.isArray(action.payload) ? action.payload : [action.payload];
58
59 keys.forEach(key => {
60 delete state.memory.hot[key];
61 delete state.memory.warm[key];
62 delete state.memory.cold[key];
63 delete state.policies.ttl[key];
64 });
65 },
66
67 compactCache: (state) => {
68 const now = Date.now();
69
70 // Remove expired entries
71 Object.keys(state.policies.ttl).forEach(key => {
72 if (state.policies.ttl[key] < now) {
73 this.removeFromAllCaches(state, key);
74 }
75 });
76
77 // Move cold cache to warm if space needed
78 if (Object.keys(state.memory.cold).length > 1000) {
79 const lruKeys = this.getLRUKeys(state.memory.cold, 500);
80 lruKeys.forEach(key => delete state.memory.cold[key]);
81 }
82 }
83 }
84});1// Circuit breaker for API calls
2class CircuitBreaker {
3 private failures: number = 0;
4 private lastFailureTime: number = 0;
5 private state: 'CLOSED' | 'OPEN' | 'HALF_OPEN' = 'CLOSED';
6
7 constructor(
8 private threshold: number = 5,
9 private timeout: number = 60000,
10 private resetTimeout: number = 30000
11 ) {}
12
13 async execute<T>(operation: () => Promise<T>): Promise<T> {
14 if (this.state === 'OPEN') {
15 if (Date.now() - this.lastFailureTime >= this.resetTimeout) {
16 this.state = 'HALF_OPEN';
17 } else {
18 throw new Error('Circuit breaker is OPEN');
19 }
20 }
21
22 try {
23 const result = await operation();
24 this.onSuccess();
25 return result;
26 } catch (error) {
27 this.onFailure();
28 throw error;
29 }
30 }
31
32 private onSuccess() {
33 this.failures = 0;
34 this.state = 'CLOSED';
35 }
36
37 private onFailure() {
38 this.failures++;
39 this.lastFailureTime = Date.now();
40
41 if (this.failures >= this.threshold) {
42 this.state = 'OPEN';
43 }
44 }
45}
46
47// Integration with Redux thunks
48const apiCircuitBreaker = new CircuitBreaker(5, 60000, 30000);
49
50export const fetchDataWithCircuitBreaker = createAsyncThunk(
51 'data/fetchWithCircuitBreaker',
52 async (params: any, { rejectWithValue }) => {
53 try {
54 return await apiCircuitBreaker.execute(() =>
55 fetch('/api/data').then(res => res.json())
56 );
57 } catch (error) {
58 return rejectWithValue({
59 message: error instanceof Error ? error.message : 'Circuit breaker error',
60 type: 'CIRCUIT_BREAKER_ERROR'
61 });
62 }
63 }
64);1// State backup and recovery system
2const stateRecoverySlice = createSlice({
3 name: 'recovery',
4 initialState: {
5 snapshots: [] as StateSnapshot[],
6 currentSnapshot: null as StateSnapshot | null,
7 recoveryMode: false,
8 autoBackupEnabled: true
9 },
10 reducers: {
11 createSnapshot: (state, action: PayloadAction<{ label: string; appState: any }>) => {
12 const snapshot: StateSnapshot = {
13 id: generateId(),
14 label: action.payload.label,
15 timestamp: Date.now(),
16 state: action.payload.appState,
17 version: '1.0.0'
18 };
19
20 state.snapshots.push(snapshot);
21
22 // Keep only last 10 snapshots
23 if (state.snapshots.length > 10) {
24 state.snapshots = state.snapshots.slice(-10);
25 }
26 },
27
28 restoreFromSnapshot: (state, action: PayloadAction<string>) => {
29 const snapshot = state.snapshots.find(s => s.id === action.payload);
30 if (snapshot) {
31 state.currentSnapshot = snapshot;
32 state.recoveryMode = true;
33 }
34 },
35
36 exitRecoveryMode: (state) => {
37 state.recoveryMode = false;
38 state.currentSnapshot = null;
39 }
40 }
41});
42
43// Auto-backup middleware
44const autoBackupMiddleware: Middleware = (store) => (next) => (action) => {
45 const result = next(action);
46
47 const state = store.getState() as RootState;
48
49 // Create automatic backups on critical actions
50 if (action.type.includes('DELETE') || action.type.includes('RESET')) {
51 store.dispatch(createSnapshot({
52 label: `Auto-backup before ${action.type}`,
53 appState: state
54 }));
55 }
56
57 return result;
58};1// Virtual state management for large datasets
2interface VirtualState<T> {
3 visibleRange: { start: number; end: number };
4 bufferSize: number;
5 totalItems: number;
6 loadedChunks: Map<number, T[]>;
7 loadingChunks: Set<number>;
8}
9
10const createVirtualSlice = <T>(name: string) => createSlice({
11 name,
12 initialState: {
13 visibleRange: { start: 0, end: 100 },
14 bufferSize: 50,
15 totalItems: 0,
16 loadedChunks: new Map(),
17 loadingChunks: new Set()
18 } as VirtualState<T>,
19 reducers: {
20 setVisibleRange: (state, action: PayloadAction<{ start: number; end: number }>) => {
21 state.visibleRange = action.payload;
22
23 // Trigger loading for chunks that are needed but not loaded
24 const requiredChunks = this.getRequiredChunks(action.payload, state.bufferSize);
25 requiredChunks.forEach(chunkIndex => {
26 if (!state.loadedChunks.has(chunkIndex) && !state.loadingChunks.has(chunkIndex)) {
27 state.loadingChunks.add(chunkIndex);
28 // Dispatch async action to load chunk
29 }
30 });
31 },
32
33 chunkLoaded: (state, action: PayloadAction<{ chunkIndex: number; data: T[] }>) => {
34 const { chunkIndex, data } = action.payload;
35 state.loadedChunks.set(chunkIndex, data);
36 state.loadingChunks.delete(chunkIndex);
37 },
38
39 unloadDistantChunks: (state) => {
40 const { start, end } = state.visibleRange;
41 const keepDistance = state.bufferSize * 2;
42
43 state.loadedChunks.forEach((_, chunkIndex) => {
44 const chunkStart = chunkIndex * 100;
45 const chunkEnd = chunkStart + 100;
46
47 if (chunkEnd < start - keepDistance || chunkStart > end + keepDistance) {
48 state.loadedChunks.delete(chunkIndex);
49 }
50 });
51 }
52 }
53});1// Web Worker integration for heavy computations
2class StateProcessingWorker {
3 private worker: Worker;
4 private taskQueue: Map<string, { resolve: Function; reject: Function }> = new Map();
5
6 constructor() {
7 this.worker = new Worker('/workers/state-processor.js');
8 this.worker.onmessage = this.handleWorkerMessage.bind(this);
9 }
10
11 async processLargeDataset(data: any[], operation: string): Promise<any> {
12 const taskId = generateId();
13
14 return new Promise((resolve, reject) => {
15 this.taskQueue.set(taskId, { resolve, reject });
16
17 this.worker.postMessage({
18 taskId,
19 operation,
20 data
21 });
22 });
23 }
24
25 private handleWorkerMessage(event: MessageEvent) {
26 const { taskId, result, error } = event.data;
27 const task = this.taskQueue.get(taskId);
28
29 if (task) {
30 if (error) {
31 task.reject(new Error(error));
32 } else {
33 task.resolve(result);
34 }
35 this.taskQueue.delete(taskId);
36 }
37 }
38}
39
40// Background processing thunk
41export const processDataInBackground = createAsyncThunk(
42 'data/processInBackground',
43 async (data: any[], { dispatch }) => {
44 const worker = new StateProcessingWorker();
45
46 try {
47 // Show loading state
48 dispatch(setProcessingState('loading'));
49
50 // Process data in web worker
51 const result = await worker.processLargeDataset(data, 'normalize');
52
53 // Update state with processed data
54 dispatch(setProcessingState('completed'));
55 return result;
56 } catch (error) {
57 dispatch(setProcessingState('error'));
58 throw error;
59 }
60 }
61);1// State migration system
2interface StateVersion {
3 version: string;
4 migrate: (oldState: any) => any;
5 validate: (state: any) => boolean;
6}
7
8const stateMigrations: StateVersion[] = [
9 {
10 version: '1.0.0',
11 migrate: (state: any) => state,
12 validate: (state: any) => !!state.users
13 },
14 {
15 version: '1.1.0',
16 migrate: (state: any) => ({
17 ...state,
18 users: {
19 ...state.users,
20 profiles: state.users.users.map(user => ({
21 ...user,
22 preferences: {}
23 }))
24 }
25 }),
26 validate: (state: any) => !!state.users.profiles
27 },
28 {
29 version: '2.0.0',
30 migrate: (state: any) => ({
31 userManagement: {
32 users: state.users,
33 authentication: state.auth
34 },
35 contentManagement: {
36 articles: state.articles || {}
37 }
38 }),
39 validate: (state: any) => !!state.userManagement && !!state.contentManagement
40 }
41];
42
43const migrateState = (persistedState: any, currentVersion: string): any => {
44 const stateVersion = persistedState._version || '1.0.0';
45
46 if (stateVersion === currentVersion) {
47 return persistedState;
48 }
49
50 let migratedState = persistedState;
51 let currentIndex = stateMigrations.findIndex(m => m.version === stateVersion);
52
53 if (currentIndex === -1) {
54 throw new Error(`Unknown state version: ${stateVersion}`);
55 }
56
57 // Apply migrations sequentially
58 for (let i = currentIndex + 1; i < stateMigrations.length; i++) {
59 const migration = stateMigrations[i];
60 migratedState = migration.migrate(migratedState);
61
62 if (!migration.validate(migratedState)) {
63 throw new Error(`State migration to ${migration.version} failed validation`);
64 }
65
66 migratedState._version = migration.version;
67
68 if (migration.version === currentVersion) {
69 break;
70 }
71 }
72
73 return migratedState;
74};1// Production monitoring system
2class StateMonitor {
3 private metrics: Map<string, any> = new Map();
4 private alerts: AlertRule[] = [];
5
6 constructor(private config: MonitoringConfig) {
7 this.setupPerformanceObserver();
8 this.setupErrorTracking();
9 }
10
11 trackStateChange(action: any, prevState: any, nextState: any) {
12 const stateSize = JSON.stringify(nextState).length;
13 const actionDuration = performance.now() - action.timestamp;
14
15 this.metrics.set('stateSize', stateSize);
16 this.metrics.set('lastActionDuration', actionDuration);
17
18 // Check for performance issues
19 if (stateSize > this.config.maxStateSize) {
20 this.triggerAlert('STATE_SIZE_EXCEEDED', { stateSize });
21 }
22
23 if (actionDuration > this.config.slowActionThreshold) {
24 this.triggerAlert('SLOW_ACTION', { action: action.type, duration: actionDuration });
25 }
26
27 // Send to analytics service
28 if (this.config.enableAnalytics) {
29 this.sendAnalytics({
30 event: 'state_change',
31 action: action.type,
32 duration: actionDuration,
33 stateSize
34 });
35 }
36 }
37
38 private setupPerformanceObserver() {
39 if ('PerformanceObserver' in window) {
40 const observer = new PerformanceObserver((list) => {
41 list.getEntries().forEach((entry) => {
42 if (entry.name.includes('redux')) {
43 this.metrics.set('performanceEntry', entry);
44 }
45 });
46 });
47
48 observer.observe({ entryTypes: ['measure'] });
49 }
50 }
51
52 private triggerAlert(type: string, data: any) {
53 const alert = {
54 type,
55 timestamp: Date.now(),
56 data,
57 severity: this.getAlertSeverity(type)
58 };
59
60 // Send to monitoring service
61 if (this.config.alertWebhook) {
62 fetch(this.config.alertWebhook, {
63 method: 'POST',
64 headers: { 'Content-Type': 'application/json' },
65 body: JSON.stringify(alert)
66 });
67 }
68 }
69}
70
71// Monitoring middleware
72const monitoringMiddleware: Middleware = (store) => (next) => (action) => {
73 const startTime = performance.now();
74 const prevState = store.getState();
75
76 const result = next(action);
77
78 const endTime = performance.now();
79 const nextState = store.getState();
80
81 // Track performance and state changes
82 stateMonitor.trackStateChange(
83 { ...action, timestamp: startTime, duration: endTime - startTime },
84 prevState,
85 nextState
86 );
87
88 return result;
89};1// Environment-specific store configuration
2const createProductionStore = (preloadedState?: any) => {
3 const middleware = [
4 // Core middleware
5 thunk,
6
7 // Production middleware
8 ...(process.env.NODE_ENV === 'production'
9 ? [monitoringMiddleware, errorReportingMiddleware]
10 : [loggerMiddleware, devToolsMiddleware]
11 ),
12
13 // Feature flags middleware
14 featureFlagsMiddleware,
15
16 // Performance middleware
17 performanceMiddleware
18 ];
19
20 return configureStore({
21 reducer: rootReducer,
22 middleware,
23 preloadedState: preloadedState ? migrateState(preloadedState, CURRENT_VERSION) : undefined,
24 devTools: process.env.NODE_ENV !== 'production',
25
26 // Production optimizations
27 immutableCheck: process.env.NODE_ENV !== 'production',
28 serializableCheck: process.env.NODE_ENV !== 'production' ? {
29 ignoredActions: ['persist/PERSIST', 'analytics/track']
30 } : false
31 });
32};
33
34// Feature flags integration
35const featureFlagsMiddleware: Middleware = (store) => (next) => (action) => {
36 const state = store.getState() as RootState;
37 const featureFlags = state.featureFlags;
38
39 // Block actions based on feature flags
40 if (action.type.startsWith('newFeature/') && !featureFlags.newFeatureEnabled) {
41 console.warn(`Action ${action.type} blocked by feature flag`);
42 return;
43 }
44
45 return next(action);
46};1// Advanced persistence strategy
2class StatePersistence {
3 private storage: Storage;
4 private compression: boolean;
5 private encryption: boolean;
6
7 constructor(config: PersistenceConfig) {
8 this.storage = config.storage;
9 this.compression = config.compression || false;
10 this.encryption = config.encryption || false;
11 }
12
13 async persistState(state: any): Promise<void> {
14 try {
15 let serializedState = JSON.stringify(state);
16
17 if (this.compression) {
18 serializedState = await this.compress(serializedState);
19 }
20
21 if (this.encryption) {
22 serializedState = await this.encrypt(serializedState);
23 }
24
25 this.storage.setItem('appState', serializedState);
26 } catch (error) {
27 console.error('Failed to persist state:', error);
28 }
29 }
30
31 async loadState(): Promise<any | undefined> {
32 try {
33 let serializedState = this.storage.getItem('appState');
34
35 if (!serializedState) {
36 return undefined;
37 }
38
39 if (this.encryption) {
40 serializedState = await this.decrypt(serializedState);
41 }
42
43 if (this.compression) {
44 serializedState = await this.decompress(serializedState);
45 }
46
47 return JSON.parse(serializedState);
48 } catch (error) {
49 console.error('Failed to load state:', error);
50 return undefined;
51 }
52 }
53}
54
55// State hydration with validation
56const hydrateStore = async (): Promise<Store> => {
57 const persistence = new StatePersistence({
58 storage: localStorage,
59 compression: true,
60 encryption: false
61 });
62
63 const persistedState = await persistence.loadState();
64
65 if (persistedState) {
66 // Validate persisted state
67 const isValid = validateStateSchema(persistedState);
68
69 if (isValid) {
70 const migratedState = migrateState(persistedState, CURRENT_VERSION);
71 return createProductionStore(migratedState);
72 } else {
73 console.warn('Invalid persisted state, using default state');
74 }
75 }
76
77 return createProductionStore();
78};Implement a production-ready state architecture with:
Congratulations! You've completed the comprehensive React State Management course. You now have the knowledge and tools to build enterprise-grade applications with sophisticated state management architectures.
Ready to build the next generation of React applications? You have all the tools you need!
Your progress is saved in this browser, on this device only.