0
# Core Proxy System
1
2
Foundation of Valtio's reactivity providing proxy creation, immutable snapshots, and change subscriptions. The core system enables automatic state tracking without explicit setters or reducers.
3
4
## Capabilities
5
6
### Proxy Creation
7
8
Creates a reactive proxy object that automatically tracks mutations and notifies subscribers of changes.
9
10
```typescript { .api }
11
/**
12
* Creates a reactive proxy object that can be tracked for changes
13
* @param baseObject - The object to create a proxy for (defaults to empty object)
14
* @returns A proxied version of the input object
15
* @throws Error if input is not an object
16
*/
17
function proxy<T extends object>(baseObject?: T): T;
18
```
19
20
**Usage Examples:**
21
22
```typescript
23
import { proxy } from "valtio";
24
25
// Simple state object
26
const state = proxy({ count: 0, name: "Alice" });
27
28
// Mutate directly
29
state.count++; // triggers change notifications
30
state.name = "Bob";
31
32
// Nested objects are automatically proxied
33
const appState = proxy({
34
user: { id: 1, profile: { name: "Charlie" } },
35
settings: { theme: "dark" }
36
});
37
38
// All levels are reactive
39
appState.user.profile.name = "Dave"; // triggers notifications
40
appState.settings.theme = "light";
41
42
// Arrays are also proxied
43
const listState = proxy({ items: [1, 2, 3] });
44
listState.items.push(4); // reactive
45
listState.items[0] = 10; // reactive
46
```
47
48
### Snapshot Creation
49
50
Creates an immutable snapshot of the current state of a proxy object. Snapshots are safe to read in React render functions and other contexts where immutability is important.
51
52
```typescript { .api }
53
/**
54
* Creates an immutable snapshot of the current state of a proxy object
55
* @param proxyObject - The proxy object to create a snapshot from
56
* @returns An immutable snapshot of the current state
57
*/
58
function snapshot<T extends object>(proxyObject: T): Snapshot<T>;
59
```
60
61
**Usage Examples:**
62
63
```typescript
64
import { proxy, snapshot } from "valtio";
65
66
const state = proxy({ count: 0, items: [1, 2, 3] });
67
68
// Get immutable snapshot
69
const snap = snapshot(state);
70
console.log(snap.count); // 0
71
console.log(snap.items); // [1, 2, 3]
72
73
// Snapshot is readonly - these would cause TypeScript errors:
74
// snap.count = 1; // Error: readonly property
75
// snap.items.push(4); // Error: readonly array
76
77
// Snapshots reflect current state
78
state.count = 5;
79
const newSnap = snapshot(state);
80
console.log(newSnap.count); // 5
81
```
82
83
### Change Subscriptions
84
85
Subscribes to changes in a proxy object, receiving detailed information about each mutation.
86
87
```typescript { .api }
88
/**
89
* Subscribes to changes in a proxy object
90
* @param proxyObject - The proxy object to subscribe to
91
* @param callback - Function called when the proxy object changes
92
* @param notifyInSync - If true, notifications happen synchronously
93
* @returns Unsubscribe function to stop listening for changes
94
*/
95
function subscribe<T extends object>(
96
proxyObject: T,
97
callback: (unstable_ops: Op[]) => void,
98
notifyInSync?: boolean
99
): () => void;
100
```
101
102
**Usage Examples:**
103
104
```typescript
105
import { proxy, subscribe } from "valtio";
106
107
const state = proxy({ count: 0, user: { name: "Alice" } });
108
109
// Subscribe to all changes
110
const unsubscribe = subscribe(state, (unstable_ops) => {
111
console.log("Operations:", unstable_ops);
112
// unstable_ops contains details about what changed
113
});
114
115
// Make changes
116
state.count++;
117
// Logs: [["set", ["count"], 1, 0]]
118
119
state.user.name = "Bob";
120
// Logs: [["set", ["user", "name"], "Bob", "Alice"]]
121
122
// Stop listening
123
unsubscribe();
124
125
// Synchronous notifications
126
const syncUnsub = subscribe(state, (unstable_ops) => {
127
console.log("Immediate:", unstable_ops);
128
}, true);
129
```
130
131
### Version Tracking
132
133
Gets the current version number of a proxy object, useful for debugging and advanced scenarios.
134
135
```typescript { .api }
136
/**
137
* Gets the current version number of a proxy object
138
* @param proxyObject - The proxy object to get the version of
139
* @returns The current version number, or undefined if not a proxy
140
*/
141
function getVersion(proxyObject: unknown): number | undefined;
142
```
143
144
**Usage Examples:**
145
146
```typescript
147
import { proxy, getVersion } from "valtio";
148
149
const state = proxy({ count: 0 });
150
151
console.log(getVersion(state)); // 1 (initial version)
152
153
state.count++;
154
console.log(getVersion(state)); // 2
155
156
state.count++;
157
console.log(getVersion(state)); // 3
158
159
// Non-proxy objects return undefined
160
console.log(getVersion({})); // undefined
161
```
162
163
### Reference Marking
164
165
Marks an object to be excluded from proxying, keeping it as a reference in snapshots instead of deep copying.
166
167
```typescript { .api }
168
/**
169
* Marks an object to be excluded from proxying
170
* Objects marked with ref will be kept as references in snapshots
171
* instead of being deeply copied.
172
* @param obj - The object to mark as a reference
173
* @returns The same object with a type marker
174
*/
175
function ref<T extends object>(obj: T): T & { $$valtioSnapshot: T };
176
```
177
178
**Usage Examples:**
179
180
```typescript
181
import { proxy, snapshot, ref } from "valtio";
182
183
// Without ref - objects are proxied and copied in snapshots
184
const regularState = proxy({
185
data: { heavy: "object with lots of data" }
186
});
187
188
// With ref - object is kept as reference
189
const refState = proxy({
190
data: ref({ heavy: "object with lots of data" })
191
});
192
193
const snap = snapshot(refState);
194
console.log(snap.data === refState.data); // true (same reference)
195
196
// Useful for immutable objects, class instances, or heavy data
197
class ApiClient {
198
constructor(private apiKey: string) {}
199
async fetch(url: string) { /* ... */ }
200
}
201
202
const appState = proxy({
203
client: ref(new ApiClient("key123")),
204
userData: { name: "Alice" }
205
});
206
207
// client won't be proxied, userData will be
208
```
209
210
## Types
211
212
```typescript { .api }
213
type Snapshot<T> = T extends { $$valtioSnapshot: infer S }
214
? S
215
: T extends SnapshotIgnore
216
? T
217
: T extends object
218
? { readonly [K in keyof T]: Snapshot<T[K]> }
219
: T;
220
221
type Op =
222
| [op: 'set', path: (string | symbol)[], value: unknown, prevValue: unknown]
223
| [op: 'delete', path: (string | symbol)[], prevValue: unknown];
224
225
type SnapshotIgnore =
226
| Date
227
| Map<any, any>
228
| Set<any>
229
| WeakMap<any, any>
230
| WeakSet<any>
231
| Error
232
| RegExp
233
| Function
234
| Primitive;
235
236
type Primitive = string | number | boolean | null | undefined | symbol | bigint;
237
```