Component Integration
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
Component Integration Guide
Complete guide to using Flash Persistence in your Angular components with customizable database keys and collections.
Table of Contents
- Quick Start
- Integration Methods
- Database Key Customization
- Collection Organization Strategies
- Best Practices
- Performance Considerations
- Migration Examples
Quick Start
Flash Persistence works in any component with zero configuration:
import { Component } from '@angular/core';
import { autoFlashState } from '@storage-system';
@Component({
selector: 'app-my-component',
template: `<div>{{ myState() }}</div>`
})
export class MyComponent {
// ONE LINE = Persistent state!
myState = autoFlashState('key', 'default value');
}
Integration Methods
Method 1: Direct autoFlashState (Simplest)
Best for: Quick prototyping, simple use cases
import { autoFlashState } from '@storage-system';
@Component({ selector: 'app-dashboard' })
export class DashboardComponent {
// Basic usage
theme = autoFlashState('theme', { color: 'blue' });
// Key: flash:theme
// With custom database
userPrefs = autoFlashState('preferences', {}, {
database: 'user-data'
});
// Key: user-data:flash:preferences
// With custom collection
filters = autoFlashState('filters', [], {
collection: 'dashboard'
});
// Key: flash:dashboard:filters
// With custom namespace
settings = autoFlashState('config', {}, {
namespace: 'app-v2'
});
// Key: app-v2:config
// Full customization
adminConfig = autoFlashState('settings', {}, {
database: 'admin',
namespace: 'v2',
collection: 'config',
priority: 'critical',
ttl: 24 * 60 * 60 * 1000 // 24 hours
});
// Key: admin:v2:config:settings
}
Method 2: Convenience Helpers (Recommended)
Best for: Production code, type-safety, clear intent
import {
userFlashState,
componentFlashState,
sessionFlashState,
tempFlashState,
settingsFlashState,
globalFlashState,
cacheFlashState,
featureFlashState
} from '@storage-system';
@Component({ selector: 'app-dashboard' })
export class DashboardComponent {
// User-specific state (high priority)
preferences = userFlashState('preferences', {});
// Key: flash:user:preferences
// Component-scoped (prevents collisions)
filters = componentFlashState('dashboard', 'filters', { status: 'all' });
layout = componentFlashState('dashboard', 'layout', 'grid');
// Keys: flash:dashboard:filters, flash:dashboard:layout
// Session state (24h TTL)
recentViews = sessionFlashState('recent-views', []);
// Key: flash:session:recent-views
// Temporary cache (custom TTL)
searchCache = tempFlashState('search-results', [], 15); // 15 minutes
// Key: flash:temp:search-results
// Settings (critical priority)
appTheme = settingsFlashState('theme', 'light');
// Key: flash:settings:theme
// Global shared state
currentUser = globalFlashState('current-user', null);
// Key: flash:global:current-user
// Cache with custom TTL
apiCache = cacheFlashState('products', [], 60); // 60 minutes
// Key: flash:cache:products
// Feature-scoped state
todoItems = featureFlashState('todos', 'items', []);
todoFilters = featureFlashState('todos', 'filters', {});
// Keys: flash:todos:items, flash:todos:filters
}
Method 3: Injectable Service (Service-Oriented)
Best for: Large components, service-based architecture, bulk operations
import { Component, inject } from '@angular/core';
import { FlashStateService } from '@storage-system';
@Component({ selector: 'app-settings' })
export class SettingsComponent {
private flashState = inject(FlashStateService);
// Component-scoped builder
private state = this.flashState.forComponent('app-settings');
// Create individual states
theme = this.state.state('theme', 'light');
language = this.state.state('language', 'en');
fontSize = this.state.state('fontSize', 16);
// Create bulk states
uiSettings = this.flashState.createMultiple({
sidebarCollapsed: false,
showNotifications: true,
animationsEnabled: true,
compactMode: false
}, { collection: 'ui', priority: 'normal' });
// Specialized helpers
userProfile = this.flashState.createUserState('profile', {});
sessionData = this.flashState.createSessionState('data', {});
globalConfig = this.flashState.createGlobalState('config', {});
criticalSettings = this.flashState.createSettingsState('app', {});
tempCache = this.flashState.createCacheState('api-data', [], 30);
}
Database Key Customization
Flash Persistence uses a hierarchical key structure for maximum flexibility:
Key Structure
[database]:[namespace]:[collection]:[key]
Components:
- database (optional): Top-level data partition
- namespace (default: "flash"): Logical grouping
- collection (optional): Related state organization
- key (required): Unique state identifier
Examples
| Configuration | Resulting Key | Use Case |
|---|---|---|
autoFlashState('theme', {}) |
flash:theme |
Simple state |
database: 'user-data' |
user-data:flash:theme |
User-specific database |
collection: 'dashboard' |
flash:dashboard:theme |
Component grouping |
namespace: 'app-v2' |
app-v2:theme |
Version isolation |
database: 'admin', collection: 'settings' |
admin:flash:settings:theme |
Full hierarchy |
Customization Options
interface AutoFlashStateOptions<T> {
database?: string; // Custom database name
namespace?: string; // Custom namespace (default: 'flash')
collection?: string; // Collection for grouping
priority?: 'critical' | 'high' | 'normal' | 'low';
ttl?: number; // Time-to-live in milliseconds
versioning?: {...}; // State migration config
debounceMs?: number; // Persistence delay (default: 300ms)
}
Collection Organization Strategies
1. Component-Based Organization
Group all state for a component together:
@Component({ selector: 'app-user-profile' })
export class UserProfileComponent {
bio = componentFlashState('user-profile', 'bio', '');
avatar = componentFlashState('user-profile', 'avatar', '');
preferences = componentFlashState('user-profile', 'preferences', {});
// All keys under: flash:user-profile:*
}
2. Feature-Based Organization
Group by logical features:
// Todo Feature
todos = featureFlashState('todos', 'items', []);
todoFilters = featureFlashState('todos', 'filters', {});
todoSort = featureFlashState('todos', 'sort', 'date');
// Shopping Feature
cart = featureFlashState('shopping', 'cart', []);
wishlist = featureFlashState('shopping', 'wishlist', []);
3. User-Data Organization
Separate user-specific data:
// User database for all user data
profile = autoFlashState('profile', {}, { database: 'user-data' });
settings = autoFlashState('settings', {}, { database: 'user-data' });
history = autoFlashState('history', [], { database: 'user-data' });
// Keys: user-data:flash:profile, user-data:flash:settings, etc.
4. Lifecycle-Based Organization
Organize by data lifecycle:
// Critical data (never expires, high priority)
userAuth = settingsFlashState('auth-token', null);
// Session data (expires after 24h)
recentActivity = sessionFlashState('activity', []);
// Temporary cache (expires after 30min)
apiCache = tempFlashState('api-responses', {}, 30);
Best Practices
1. Choose the Right Method
// ✅ GOOD: Use convenience helpers for clarity
theme = settingsFlashState('theme', 'light');
// ❌ AVOID: Manual configuration for common patterns
theme = autoFlashState('theme', 'light', {
collection: 'settings',
priority: 'critical'
});
2. Scope Your State Appropriately
// ✅ GOOD: Component-scoped to prevent collisions
filters = componentFlashState('dashboard', 'filters', {});
// ❌ AVOID: Global keys that might collide
filters = autoFlashState('filters', {}); // Which component's filters?
3. Use Appropriate TTLs
// ✅ GOOD: TTL for temporary data
searchResults = tempFlashState('search', [], 15); // 15 minutes
// ❌ AVOID: No TTL for temporary data
searchResults = autoFlashState('search', []); // Never expires!
4. Set Correct Priorities
// ✅ GOOD: Critical for essential data
authToken = settingsFlashState('auth', null); // critical priority
// ✅ GOOD: Low for caches
apiCache = cacheFlashState('data', [], 30); // low priority
// ❌ AVOID: Everything as critical
randomCache = autoFlashState('cache', [], { priority: 'critical' });
5. Organize Collections Logically
// ✅ GOOD: Clear, hierarchical organization
dashboardLayout = componentFlashState('dashboard', 'layout', 'grid');
dashboardFilters = componentFlashState('dashboard', 'filters', {});
dashboardSort = componentFlashState('dashboard', 'sort', 'date');
// ❌ AVOID: Flat structure with no organization
layout = autoFlashState('dashboard-layout', 'grid');
filters = autoFlashState('dashboard-filters', {});
sort = autoFlashState('dashboard-sort', 'date');
Performance Considerations
1. Debouncing
All state updates are automatically debounced (default: 300ms) to prevent excessive storage writes:
// Rapid updates are batched
for (let i = 0; i < 100; i++) {
counter.set(i); // Only final value persisted after 300ms
}
2. Pre-loading
Critical states are pre-loaded during app initialization for instant access:
// Configured in app.config.ts
provideIntelligentStorage({
namespace: 'my-app',
preloadStates: [
'flash:settings:theme',
'flash:user:profile',
'flash:global:current-user'
]
})
3. Caching Layers
Flash Persistence uses multiple caching layers:
- Memory cache (instant access)
- Micro-cache (sub-millisecond)
- IndexedDB (persistent)
4. Priority-Based Storage
Higher priority states use more reliable storage:
- critical: OPFS + IndexedDB (redundant)
- high: IndexedDB
- normal: IndexedDB
- low: IndexedDB with aggressive cleanup
Migration Examples
From NGXS
// BEFORE (NGXS)
@State({ name: 'theme', defaults: { color: 'blue' } })
export class ThemeState {
@Selector()
static getColor(state: ThemeStateModel) {
return state.color;
}
@Action(SetTheme)
setTheme(ctx: StateContext<ThemeStateModel>, action: SetTheme) {
ctx.patchState({ color: action.color });
}
}
// AFTER (Flash Persistence)
export class SettingsComponent {
theme = settingsFlashState('theme', { color: 'blue' });
// Use directly
getColor() {
return this.theme().color;
}
setTheme(color: string) {
this.theme.update(t => ({ ...t, color }));
}
}
From localStorage
// BEFORE (localStorage)
export class Component {
get theme() {
return JSON.parse(localStorage.getItem('theme') || '{}');
}
setTheme(theme: any) {
localStorage.setItem('theme', JSON.stringify(theme));
}
}
// AFTER (Flash Persistence)
export class Component {
theme = autoFlashState('theme', {});
// Automatic persistence, reactivity, and type-safety!
}
From Component Properties
// BEFORE (No persistence)
export class Component {
filters = signal({ status: 'all', sort: 'date' });
// Lost on refresh!
}
// AFTER (Flash Persistence)
export class Component {
filters = componentFlashState('dashboard', 'filters', {
status: 'all',
sort: 'date'
});
// Persisted across refreshes!
}
Troubleshooting
State Not Persisting
// ❌ PROBLEM: Using regular signal
myState = signal('value');
// ✅ SOLUTION: Use Flash Persistence
myState = autoFlashState('key', 'value');
Key Collisions
// ❌ PROBLEM: Same key in multiple components
// Component A
filters = autoFlashState('filters', {});
// Component B
filters = autoFlashState('filters', {}); // Collision!
// ✅ SOLUTION: Scope to component
// Component A
filters = componentFlashState('component-a', 'filters', {});
// Component B
filters = componentFlashState('component-b', 'filters', {});
Performance Issues
// ❌ PROBLEM: Too many rapid updates
for (let i = 0; i < 1000; i++) {
counter.set(i); // Excessive debounce resets
}
// ✅ SOLUTION: Batch updates
counter.set(1000); // Single update