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

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:

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:

4. Priority-Based Storage

Higher priority states use more reliable storage:

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

Next Steps