# 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) →