# State Manager Module **Centralized, Reactive State Management for Client-Side State** The State Manager Module provides a centralized state management system similar to Redux or Vuex, with support for state persistence, cross-tab synchronization, and integration with LiveComponents. --- ## Features - **Reactive State Store** - Subscribe to state changes and react automatically - **State Persistence** - Automatically save and restore state from localStorage or sessionStorage - **Cross-Tab Synchronization** - Keep state synchronized across browser tabs - **Integration with LiveComponents** - Seamless integration with LiveComponent state - **Time-Travel Debugging** - Debug state changes with history and time-travel - **Middleware Support** - Extend functionality with custom middleware --- ## Quick Start ### Basic Usage ```javascript import { StateManager } from './modules/state-manager/index.js'; // Create a state manager const store = StateManager.create({ initialState: { user: { name: '', email: '' }, cart: { items: [], total: 0 }, ui: { sidebarOpen: false } } }); // Set state store.set('user.name', 'John Doe'); store.set('cart.items', [{ id: 1, name: 'Product' }]); // Get state const userName = store.get('user.name'); const cartItems = store.get('cart.items', []); // Subscribe to changes const unsubscribe = store.subscribe('cart.items', (items) => { console.log('Cart items changed:', items); updateCartUI(items); }); // Unsubscribe unsubscribe(); ``` ### Module System Integration ```html ``` --- ## API Reference ### StateManager.create(config) Create a new StateManager instance. **Parameters**: - `config.initialState` - Initial state object - `config.maxHistorySize` - Maximum history size (default: 50) - `config.enableHistory` - Enable history for time-travel (default: false) - `config.persistence.enabled` - Enable state persistence (default: false) - `config.persistence.storage` - Storage type: 'localStorage' or 'sessionStorage' (default: 'localStorage') - `config.persistence.key` - Storage key (default: 'app-state') - `config.persistence.paths` - Array of paths to persist (empty = all) - `config.sync.enabled` - Enable cross-tab synchronization (default: false) **Example**: ```javascript const store = StateManager.create({ initialState: { user: {}, cart: {} }, persistence: { enabled: true, storage: 'localStorage', paths: ['user', 'cart'] // Only persist these paths }, sync: { enabled: true // Sync across tabs } }); ``` ### store.getState() Get the entire state object. **Returns**: `Record` ### store.get(path, defaultValue) Get state at a specific path. **Parameters**: - `path` - Dot-separated path (e.g., 'user.name') - `defaultValue` - Default value if path doesn't exist **Returns**: `any` **Example**: ```javascript const userName = store.get('user.name', 'Guest'); const cartTotal = store.get('cart.total', 0); ``` ### store.set(path, value) Set state at a specific path. **Parameters**: - `path` - Dot-separated path - `value` - Value to set **Example**: ```javascript store.set('user.name', 'John Doe'); store.set('cart.items', [{ id: 1, name: 'Product' }]); ``` ### store.dispatch(action) Dispatch an action (Redux-style). **Parameters**: - `action` - Action object with `type` property, or a thunk function **Example**: ```javascript // Simple action store.dispatch({ type: 'ADD_TO_CART', productId: 123, quantity: 1 }); // Thunk (async action) store.dispatch(async (dispatch, getState) => { const response = await fetch('/api/products'); const products = await response.json(); dispatch({ type: 'SET_PRODUCTS', products }); }); ``` ### store.subscribe(path, callback) Subscribe to state changes at a specific path. **Parameters**: - `path` - Dot-separated path, or '*' for all changes - `callback` - Callback function: `(newValue, oldValue, path) => void` **Returns**: Unsubscribe function **Example**: ```javascript const unsubscribe = store.subscribe('cart.items', (items, oldItems, path) => { console.log(`Cart items changed at ${path}:`, items); updateCartUI(items); }); // Later... unsubscribe(); ``` ### store.subscribeAll(callback) Subscribe to all state changes. **Parameters**: - `callback` - Callback function: `(state) => void` **Returns**: Unsubscribe function ### store.use(middleware) Add middleware to the state manager. **Parameters**: - `middleware` - Middleware function: `(action, getState) => action | null` **Example**: ```javascript // Logging middleware store.use((action, getState) => { console.log('Action:', action); console.log('Current state:', getState()); return action; // Return action to continue, or null to block }); // Validation middleware store.use((action, getState) => { if (action.type === 'SET' && action.path === 'user.email') { if (!isValidEmail(action.value)) { console.error('Invalid email'); return null; // Block the action } } return action; }); ``` ### store.getHistory() Get action history for time-travel debugging. **Returns**: `Array` ### store.timeTravel(index) Time-travel to a specific history point. **Parameters**: - `index` - History index ### store.reset() Reset state to initial state. ### store.destroy() Destroy the state manager and clean up resources. --- ## Integration with LiveComponents ```javascript import { StateManager } from './modules/state-manager/index.js'; import { LiveComponentManager } from './modules/livecomponent/index.js'; const store = StateManager.create(); const lcManager = LiveComponentManager.getInstance(); // Sync LiveComponent state with StateManager lcManager.on('component:state-updated', (componentId, state) => { store.set(`livecomponents.${componentId}`, state); }); // Update LiveComponent from StateManager store.subscribe('livecomponents', (state) => { Object.entries(state).forEach(([componentId, componentState]) => { lcManager.updateComponentState(componentId, componentState); }); }); ``` --- ## Use Cases ### User Preferences ```javascript const store = StateManager.create({ initialState: { preferences: { theme: 'light', language: 'en', notifications: true } }, persistence: { enabled: true, storage: 'localStorage', paths: ['preferences'] } }); // Save preference store.set('preferences.theme', 'dark'); // Load preference const theme = store.get('preferences.theme', 'light'); ``` ### Shopping Cart ```javascript const store = StateManager.create({ initialState: { cart: { items: [], total: 0 } }, persistence: { enabled: true, storage: 'sessionStorage', paths: ['cart'] }, sync: { enabled: true // Sync cart across tabs } }); // Add item store.set('cart.items', [ ...store.get('cart.items', []), { id: 1, name: 'Product', price: 99.99 } ]); // Calculate total store.subscribe('cart.items', (items) => { const total = items.reduce((sum, item) => sum + item.price, 0); store.set('cart.total', total); }); ``` ### UI State ```javascript const store = StateManager.create({ initialState: { ui: { sidebarOpen: false, modalOpen: false, activeTab: 'home' } } }); // Toggle sidebar store.set('ui.sidebarOpen', !store.get('ui.sidebarOpen')); // Subscribe to UI changes store.subscribe('ui', (uiState) => { updateUI(uiState); }); ``` --- ## Best Practices 1. **Use Scoped State Managers** - Create separate state managers for different features 2. **Persist Only Necessary Data** - Use `paths` to limit what gets persisted 3. **Use Middleware for Cross-Cutting Concerns** - Logging, validation, etc. 4. **Subscribe Selectively** - Only subscribe to paths you need 5. **Clean Up Subscriptions** - Always call unsubscribe when done --- ## Performance Considerations - State updates are synchronous and immediate - Subscriptions are called synchronously (be careful with expensive operations) - Persistence is debounced internally - Cross-tab sync uses BroadcastChannel (efficient) --- ## Browser Support - **Chrome/Edge**: 38+ - **Firefox**: 38+ - **Safari**: 15.4+ - **Mobile**: iOS 15.4+, Android Chrome 38+ **Required Features**: - ES2020 JavaScript - BroadcastChannel (for cross-tab sync) - localStorage/sessionStorage (for persistence) --- **Next**: [Validation Module](validation.md) →