Skip to content

Files

Latest commit

4f677ed · Feb 23, 2025

History

History
313 lines (228 loc) · 6.99 KB

api-reference.md

File metadata and controls

313 lines (228 loc) · 6.99 KB

API Reference

Complete documentation of Reflex's API, including all methods, options, and types.

Core API

reflex(options: ReflexOptions): Reflex

Creates a new reactive value.

Options

interface ReflexOptions<T> {
  initialValue: T;
  equals?: (prev: T, next: T) => boolean;
  middleware?: Array<(value: T) => T | Promise<T>>;
  debug?: boolean;
  onError?: (error: Error) => T;
  notifyDuringBatch?: boolean;
}
  • initialValue: The initial value of the reactive value
  • equals: Custom equality function for value comparison (optional)
  • middleware: Array of transform functions that process values before updates (optional)
  • debug: Enable debug logging (optional)
  • onError: Error handler function (optional)
  • notifyDuringBatch: Whether to notify subscribers during batch operations (optional, defaults to false)

Returns

interface Reflex<T> {
  readonly value: T;
  setValue(value: T): void;
  setValueAsync(value: T): Promise<void>;
  subscribe(subscriber: (value: T) => void): () => void;
  batch<R>(updateFn: (value: T) => R): R;
  batchAsync<R>(updateFn: (value: T) => Promise<R> | R): Promise<R>;
  addMiddleware(fn: Middleware<T>): void;
  removeMiddleware(fn: Middleware<T>): void;
}

Example

const counter = reflex({
  initialValue: 0,
  equals: (a, b) => a === b,
  middleware: [
    value => Math.max(0, value),  // Ensures non-negative
    value => Math.round(value)    // Rounds to integer
  ],
  debug: true,
  onError: () => 0,
  notifyDuringBatch: false  // Default behavior
});

// Basic usage
counter.setValue(5);
console.log(counter.value); // 5

// Middleware transforms values
counter.setValue(-3);
console.log(counter.value); // 0 (due to Math.max middleware)
counter.setValue(3.7);
console.log(counter.value); // 4 (due to Math.round middleware)

// Batch operations
counter.batch(() => {
  counter.setValue(10);  // No notification yet
  counter.setValue(20);  // No notification yet
}); // Subscribers notified once with final value 20

deepReflex(options: DeepReflexOptions): Reflex

Creates a deeply reactive value for objects and arrays.

Options

interface DeepReflexOptions<T> extends ReflexOptions<T> {
  onPropertyChange?: (path: PropertyPath, value: unknown) => void;
}

type PropertyPath = Array<string | number>;
  • Includes all options from ReflexOptions
  • onPropertyChange: Callback for nested property changes, receives the path to the changed property and its new value

Example

const user = deepReflex({
  initialValue: {
    profile: { name: 'John' }
  },
  onPropertyChange: (path, value) => {
    console.log(`${path.join('.')} changed to:`, value);
  }
});

// Direct property modification
user.value.profile.name = 'Jane';
// Logs: "profile.name changed to: Jane"

// Batch property updates
user.batch(value => {
  value.profile.name = 'Alice';
  value.profile.age = 30;
}); 
// Logs after batch completes:
// "profile.name changed to: Alice"
// "profile.age changed to: 30"

computed<TDeps extends any[], TResult>(

dependencies: [...Reflex], compute: (values: TDeps) => TResult | Promise, options?: ComputedOptions ): Reflex

Creates a computed value from other reactive values. The computed value updates automatically when any of its dependencies change.

Options

interface ComputedOptions<T> {
  equals?: (prev: T, next: T) => boolean;
  debug?: boolean;
}

Example

const value1 = reflex({ initialValue: 10 });
const value2 = reflex({ initialValue: 20 });

const sum = computed(
  [value1, value2],
  ([a, b]) => a + b
);

// Subscribe to receive updates
sum.subscribe(value => console.log('Sum changed:', value));
console.log(sum.value); // 30

value1.setValue(15);
console.log(sum.value); // 35

Operators

map<T, R>(fn: (value: T) => R): Operator<T, R>

Transforms values using a mapping function.

const doubled = numbers.map(n => n * 2);

filter(predicate: (value: T) => boolean): Operator<T, T>

Filters values based on a predicate.

const positiveOnly = numbers.filter(n => n > 0);

combine<T extends any[]>(sources: [...Reflex]): Reflex

Combines multiple reactive values into an array. The combined value updates whenever any source value changes.

const value1 = reflex({ initialValue: 'A' });
const value2 = reflex({ initialValue: 'B' });
const value3 = reflex({ initialValue: 'C' });

const combined = combine([value1, value2, value3]);
console.log(combined.value); // ['A', 'B', 'C']

value2.setValue('X');
console.log(combined.value); // ['A', 'X', 'C']

buffer(options: BufferOptions): Operator<T, T[]>

Buffers values before emission.

interface BufferOptions {
  size?: number;
  time?: number;
}

const buffered = value.buffer({
  size: 10,
  time: 1000
});

sample(interval: number): Operator<T, T>

Samples values at regular intervals.

const sampled = value.sample(1000); // One value per second

throttle(time: number): Operator<T, T>

Limits the rate of emissions.

const throttled = value.throttle(500);

Utility Types

Operator<TInput, TOutput>

type Operator<TInput, TOutput> = (source: Reflex<TInput>) => Reflex<TOutput>;

PropertyPath

type PropertyPath = Array<string | number>;

Used in deep reactive values to track the path to changed properties.

Middleware

type Middleware<T> = (value: T) => T | Promise<T>;

Transform functions that process values before they are stored or emitted.

Subscriber

type Subscriber<T> = (value: T) => void;

Callback function type for subscribing to value changes.

Unsubscribe

type Unsubscribe = () => void;

Function returned by subscribe that removes the subscription when called.

Static Methods

Reflex.batch(fn: () => void): void

Batches multiple updates into a single notification.

Reflex.batch(() => {
  value1.setValue(1);
  value2.setValue(2);
});

Reflex.isReflex(value: any): boolean

Type guard to check if a value is a Reflex instance.

if (Reflex.isReflex(value)) {
  // value is a Reflex instance
}

Error Handling

ReflexError

Base error class for Reflex-specific errors.

class ReflexError extends Error {
  constructor(message: string) {
    super(`[Reflex] ${message}`);
  }
}

Common Error Types

class CircularDependencyError extends ReflexError {}
class InvalidValueError extends ReflexError {}
class DisposedError extends ReflexError {}

Next Steps