0
# Core Observables
1
2
Core observable creation and manipulation functions for reactive state management. These functions form the foundation of Legend State's reactive system.
3
4
## Capabilities
5
6
### Observable Creation
7
8
Creates observables from values with proxy-based reactivity.
9
10
```typescript { .api }
11
/**
12
* Creates an observable from any value with automatic proxy wrapping
13
* @param value - Initial value for the observable
14
* @returns Observable wrapper around the value
15
*/
16
function observable<T>(value?: T): Observable<T>;
17
/**
18
* Creates an observable from a Promise value
19
* @param value - Promise to wrap in observable
20
* @returns Observable that includes loading state
21
*/
22
function observable<T>(value: Promise<T>): Observable<T & WithState>;
23
24
/**
25
* Creates a primitive observable that wraps a single value
26
* @param value - Initial primitive value
27
* @returns ObservablePrimitive for the value
28
*/
29
function observablePrimitive<T>(value?: T): ObservablePrimitive<T>;
30
/**
31
* Creates a primitive observable from a Promise value
32
* @param value - Promise to wrap in observable
33
* @returns ObservablePrimitive that includes loading state
34
*/
35
function observablePrimitive<T>(value: Promise<T>): ObservablePrimitive<T & WithState>;
36
```
37
38
### Computed Observables
39
40
Creates computed values that automatically update when dependencies change.
41
42
```typescript { .api }
43
/**
44
* Creates a computed observable that automatically tracks dependencies
45
* @param compute - Function to compute the value
46
* @returns Computed observable that updates when dependencies change
47
*/
48
function computed<T>(compute: () => T): ObservableComputed<T>;
49
50
/**
51
* Creates a two-way computed observable with custom setter
52
* @param compute - Function to compute the value
53
* @param set - Function to handle value updates
54
* @returns Two-way computed observable
55
*/
56
function computed<T, T2 = T>(
57
compute: () => T,
58
set: (value: T2) => void
59
): ObservableComputedTwoWay<T, T2>;
60
```
61
62
### Observable Tracking
63
64
Track selector execution and manage observable change listening.
65
66
```typescript { .api }
67
/**
68
* Tracks a selector function and sets up automatic updates
69
* @param selector - Function to track for changes
70
* @param update - Update function called when dependencies change
71
* @param observeEvent - Optional observe event for cancellation
72
* @param observeOptions - Options for observation behavior
73
* @returns Object with value, dispose function, and resubscribe function
74
*/
75
function trackSelector<T>(
76
selector: Selector<T>,
77
update: (params: ListenerParams) => void,
78
observeEvent?: ObserveEvent<T>,
79
observeOptions?: ObserveOptions
80
): { value: T; dispose?: () => void; resubscribe?: () => () => void };
81
82
/**
83
* Sets up a change listener on a node value
84
* @param node - The node to listen to
85
* @param callback - Callback function for changes
86
* @param options - Listener options
87
* @returns Function to dispose the listener
88
*/
89
function onChange(
90
node: NodeValue,
91
callback: ListenerFn,
92
options?: {
93
trackingType?: TrackingType;
94
initial?: boolean;
95
immediate?: boolean;
96
noArgs?: boolean;
97
}
98
): () => void;
99
```
100
101
### Batching Operations
102
103
Groups multiple observable updates into a single batch to optimize performance.
104
105
```typescript { .api }
106
/**
107
* Executes function with all observable updates batched
108
* @param fn - Function to execute with batched updates
109
*/
110
function batch(fn: () => void): void;
111
112
/**
113
* Starts batching mode for manual control
114
*/
115
function beginBatch(): void;
116
117
/**
118
* Ends batching mode and flushes pending updates
119
*/
120
function endBatch(): void;
121
```
122
123
### Events
124
125
Creates event emitters for decoupled communication.
126
127
```typescript { .api }
128
/**
129
* Creates an event emitter
130
* @returns Event emitter instance
131
*/
132
function event(): EventEmitter;
133
134
interface EventEmitter {
135
fire(data?: any): void;
136
on(callback: (data?: any) => void): () => void;
137
}
138
```
139
140
### Observer Function
141
142
Sets up observers that react to observable changes.
143
144
```typescript { .api }
145
/**
146
* Observes changes to observables and executes reaction function
147
* @param selector - Function that accesses observables to track
148
* @param reaction - Function called when dependencies change
149
* @returns Dispose function to stop observing
150
*/
151
function observe<T>(
152
selector: () => T,
153
reaction: (value: T) => void
154
): () => void;
155
```
156
157
### When Functions
158
159
Provides Promise-based waiting for specific conditions.
160
161
```typescript { .api }
162
/**
163
* Returns a Promise that resolves when the predicate returns truthy
164
* @param predicate - Function to evaluate for truthiness
165
* @returns Promise that resolves with the truthy value
166
*/
167
function when<T>(predicate: () => T): Promise<T>;
168
169
/**
170
* Like when() but waits for observable values to be ready (not loading)
171
* @param predicate - Function to evaluate for ready state
172
* @returns Promise that resolves when value is ready
173
*/
174
function whenReady<T>(predicate: () => T): Promise<T>;
175
```
176
177
### Proxy Creation
178
179
Creates observable proxies for existing objects.
180
181
```typescript { .api }
182
/**
183
* Creates an observable proxy around an existing object
184
* @param target - Object to make observable
185
* @returns Observable proxy of the target object
186
*/
187
function proxy<T>(target: T): ObservableProxy<T>;
188
```
189
190
### Selector Tracking
191
192
Provides dependency tracking utilities for advanced use cases.
193
194
```typescript { .api }
195
/**
196
* Tracks dependencies of a selector function
197
* @param selector - Function to track dependencies for
198
* @returns Object with selector and tracking information
199
*/
200
function trackSelector<T>(selector: () => T): TrackedSelector<T>;
201
202
interface TrackedSelector<T> {
203
selector: () => T;
204
dependencies: Observable[];
205
dispose: () => void;
206
}
207
```
208
209
## Observable Interface
210
211
```typescript { .api }
212
interface Observable<T> {
213
/** Get the current value, tracking for changes */
214
get(): T;
215
/** Get the current value without tracking for changes */
216
peek(): T;
217
/** Set a new value */
218
set(value: T | ((prev: T) => T) | Promise<T>): void;
219
/** Listen for changes to this observable */
220
onChange(
221
callback: ListenerFn<T>,
222
options?: ChangeListenerOptions
223
): () => void;
224
/** Assign properties to object observables */
225
assign(value: Partial<T>): void;
226
/** Delete this observable */
227
delete(): void;
228
}
229
230
interface ObservablePrimitive<T> extends Observable<T> {
231
/** Toggle boolean values */
232
toggle(): T; // Only available for boolean types
233
}
234
235
interface ChangeListenerOptions {
236
trackingType?: boolean | symbol;
237
initial?: boolean;
238
immediate?: boolean;
239
noArgs?: boolean;
240
}
241
```
242
243
**Usage Examples:**
244
245
```typescript
246
import { observable, computed, batch, when } from "@legendapp/state";
247
248
// Create observables
249
const counter$ = observable(0);
250
const user$ = observable({
251
name: "Alice",
252
age: 30,
253
preferences: {
254
theme: "dark"
255
}
256
});
257
258
// Create computed values
259
const doubled$ = computed(() => counter$.get() * 2);
260
const greeting$ = computed(() => `Hello, ${user$.name.get()}!`);
261
262
// Batch updates
263
batch(() => {
264
counter$.set(5);
265
user$.name.set("Bob");
266
user$.age.set(25);
267
}); // Only fires listeners once at the end
268
269
// Wait for conditions
270
await when(() => counter$.get() > 10);
271
console.log("Counter exceeded 10!");
272
273
// Listen for changes
274
const dispose = user$.onChange(({ value }) => {
275
console.log("User changed:", value);
276
});
277
278
// Access nested properties
279
user$.preferences.theme.set("light");
280
console.log(user$.preferences.theme.get()); // "light"
281
282
// Clean up
283
dispose();
284
```