Skip to content

@xcomputed Decorator

The @xcomputed decorator is used to create computed properties in widgets. These properties, defined with getter methods, are automatically recalculated when their dependent values change, and their results are cached.

Basic Usage

Syntax

Manual Dependency Declaration

typescript
@xcomputed({ dependencies: ['property1', 'property2'] })
get computedValue(): returnType {
  return computation;
}

Automatic Dependency Detection

typescript
@xcomputed({ autoDetectDependencies: true })
get computedValue(): returnType {
  // Used properties are automatically detected
  return computation;
}

Examples

Form Validation

Shopping Cart

Nested Dependencies

Performance Optimization

Cache Mechanism

typescript
export class OptimizedWidget {
  @xproperty()
  largeData: number[] = [];
  
  // Expensive calculation - only runs when largeData changes
  @xcomputed({ dependencies: ['largeData'] })
  get expensiveCalculation(): number {
    console.log('Calculating...'); // Only when necessary
    return this.largeData.reduce((sum, num, i) => {
      return sum + (num * Math.pow(i + 1, 2));
    }, 0);
  }
  
  // Cached result
  @xcomputed({ dependencies: ['expensiveCalculation'] })
  get formattedResult(): string {
    return `Result: ${this.expensiveCalculation.toLocaleString()}`;
  }
}

Manual Cache Invalidation

typescript
import { invalidateComputed, invalidateAllComputed } from '@xcons/widget';

export class ManualInvalidationWidget {
  @xproperty()
  data: string = '';
  
  @xcomputed({ dependencies: ['data'] })
  get processedData(): string {
    return this.data.toUpperCase();
  }
  
  // Clear a single computed property
  clearCache(): void {
    invalidateComputed(this, 'processedData');
  }
  
  // Clear all computed properties
  clearAllCaches(): void {
    invalidateAllComputed(this);
  }
}

Error Handling

typescript
export class SafeComputedWidget {
  @xproperty()
  data: any = null;
  
  @xcomputed({ dependencies: ['data'] })
  get safeValue(): string {
    try {
      if (!this.data) return 'No data';
      return this.data.value.toString();
    } catch (error) {
      console.error('Computed error:', error);
      return 'Error occurred';
    }
  }
  
  @xcomputed({ dependencies: ['data'] })
  get fallbackValue(): string {
    return this.data?.value?.toString() ?? 'Default value';
  }
}

Tips

✅ Correct Usage

typescript
// Explicitly declare dependencies
@xcomputed({ dependencies: ['prop1', 'prop2'] })
get result(): string {
  return `${this.prop1} - ${this.prop2}`;
}

// Use computed for complex calculations
@xcomputed({ dependencies: ['items'] })
get totalPrice(): number {
  return this.items.reduce((sum, item) => sum + item.price, 0);
}

// Chained computed properties
@xcomputed({ dependencies: ['firstName', 'lastName'] })
get fullName(): string {
  return `${this.firstName} ${this.lastName}`;
}

@xcomputed({ dependencies: ['fullName'] })
get greeting(): string {
  return `Hello, ${this.fullName}!`;
}

❌ Incorrect Usage

typescript
// Creating side effects
@xcomputed({ dependencies: ['count'] })
get doubleCount(): number {
  this.lastCalculated = Date.now(); // ❌ Side effect
  return this.count * 2;
}

// Asynchronous operations
@xcomputed({ dependencies: ['id'] })
get user(): Promise<User> { // ❌ Async computed not supported
  return fetch(`/api/users/${this.id}`);
}

// Using with setter
@xcomputed({ dependencies: ['value'] })
get computed(): number {
  return this.value * 2;
}
set computed(val: number) { // ❌ Computed should only be getter
  this.value = val / 2;
}

Summary

With the @xcomputed decorator:

  • ✅ Create computed properties
  • ✅ Automatic cache mechanism
  • ✅ Dependency tracking
  • ✅ Automatic or manual dependency detection
  • ✅ Nested dependencies
  • ✅ Performance optimization
  • ✅ Manual cache invalidation

Computed properties help you create performant and reactive user interfaces by optimizing complex calculations in widgets.