0
# Reactive Utilities
1
2
Core utilities for working with Solid.js reactivity system, including accessor manipulation, signal creation, and lifecycle management. These functions are designed to integrate seamlessly with Solid.js's reactive patterns and signal-based state management.
3
4
## Capabilities
5
6
### MaybeAccessor Access
7
8
Functions for working with values that may or may not be accessors (reactive functions).
9
10
```typescript { .api }
11
/**
12
* Accesses the value of a MaybeAccessor
13
* @param v - Value or accessor function to access
14
* @returns The accessed value
15
*/
16
function access<T extends MaybeAccessor<any>>(v: T): MaybeAccessorValue<T>;
17
18
/**
19
* Access an array of MaybeAccessors
20
* @param list - Array of values or accessor functions
21
* @returns Array of accessed values
22
*/
23
function accessArray<A extends MaybeAccessor<any>>(
24
list: readonly A[]
25
): MaybeAccessorValue<A>[];
26
27
/**
28
* Run the function if the accessed value is not undefined nor null
29
* @param value - MaybeAccessor to check and access
30
* @param fn - Function to run with the non-null value
31
*/
32
function withAccess<T, A extends MaybeAccessor<T>, V = MaybeAccessorValue<A>>(
33
value: A,
34
fn: (value: NonNullable<V>) => void
35
): void;
36
37
/**
38
* Convert MaybeAccessor to Accessor
39
* @param v - Value or accessor to convert
40
* @returns Accessor function
41
*/
42
function asAccessor<A extends MaybeAccessor<unknown>>(
43
v: A
44
): Accessor<MaybeAccessorValue<A>>;
45
46
/**
47
* If value is a function – call it with given arguments – otherwise get the value as is
48
* @param valueOrFn - Value or function to access
49
* @param args - Arguments to pass if valueOrFn is a function
50
* @returns Accessed value or function result
51
*/
52
function accessWith<T>(
53
valueOrFn: T,
54
...args: T extends AnyFunction ? Parameters<T> : never
55
): T extends AnyFunction ? ReturnType<T> : T;
56
```
57
58
**Usage Examples:**
59
60
```typescript
61
import { createSignal } from "solid-js";
62
import { access, accessArray, withAccess, asAccessor } from "@solid-primitives/utils";
63
64
// Basic access
65
const value = access("hello"); // "hello"
66
const signalValue = access(() => "world"); // "world"
67
68
// Array access
69
const values = accessArray([1, () => 2, 3]); // [1, 2, 3]
70
71
// Conditional access
72
withAccess(() => "value", (val) => {
73
console.log(val); // "value"
74
});
75
76
// Convert to accessor
77
const accessor = asAccessor("static value");
78
console.log(accessor()); // "static value"
79
```
80
81
### Signal Creation
82
83
Enhanced signal creation functions with special capabilities like hydration support.
84
85
```typescript { .api }
86
/**
87
* A hydratable version of createSignal. Uses serverValue on server and update function on client.
88
* During hydration uses serverValue as initial and updates once hydration is complete.
89
* @param serverValue - Initial value for server
90
* @param update - Function called on client to initialize value
91
* @param options - Signal options
92
* @returns Signal tuple [state, setState]
93
*/
94
function createHydratableSignal<T>(
95
serverValue: T,
96
update: () => T,
97
options?: SignalOptions<T>
98
): ReturnType<typeof createSignal<T>>;
99
100
/** @deprecated use createHydratableSignal instead */
101
const createHydrateSignal: typeof createHydratableSignal;
102
```
103
104
**Usage Examples:**
105
106
```typescript
107
import { createHydratableSignal } from "@solid-primitives/utils";
108
109
// Server-side rendering compatible signal
110
const [theme, setTheme] = createHydratableSignal(
111
"light", // Server default
112
() => localStorage.getItem("theme") || "light" // Client initialization
113
);
114
115
// With options
116
const [count, setCount] = createHydratableSignal(
117
0,
118
() => parseInt(sessionStorage.getItem("count") || "0"),
119
{ equals: false }
120
);
121
```
122
123
### Deferred Effects
124
125
Advanced effect utilities for handling delayed and conditional reactive updates.
126
127
```typescript { .api }
128
/**
129
* Solid's `on` helper, but always defers and returns provided initial value instead of undefined
130
* @param deps - Dependencies to watch (accessor or array of accessors)
131
* @param fn - Effect function
132
* @param initialValue - Initial value to return
133
* @returns Effect function
134
*/
135
function defer<S, Next extends Prev, Prev = Next>(
136
deps: AccessorArray<S> | Accessor<S>,
137
fn: (input: S, prevInput: S, prev: undefined | NoInfer<Prev>) => Next,
138
initialValue: Next
139
): EffectFunction<undefined | NoInfer<Next>, NoInfer<Next>>;
140
141
function defer<S, Next extends Prev, Prev = Next>(
142
deps: AccessorArray<S> | Accessor<S>,
143
fn: (input: S, prevInput: S, prev: undefined | NoInfer<Prev>) => Next,
144
initialValue?: undefined
145
): EffectFunction<undefined | NoInfer<Next>>;
146
```
147
148
**Usage Examples:**
149
150
```typescript
151
import { createSignal, createEffect } from "solid-js";
152
import { defer } from "@solid-primitives/utils";
153
154
const [count, setCount] = createSignal(0);
155
156
createEffect(defer(
157
count,
158
(value, prevValue, prev) => {
159
console.log(`Count changed from ${prevValue} to ${value}`);
160
return value * 2;
161
},
162
0 // Initial value
163
));
164
```
165
166
### Lifecycle Utilities
167
168
Functions for working with Solid.js lifecycle hooks and cleanup.
169
170
```typescript { .api }
171
/**
172
* Solid's onCleanup that doesn't warn in development if used outside of a component
173
*/
174
const tryOnCleanup: typeof onCleanup;
175
```
176
177
### Callback Management
178
179
Utilities for managing and executing multiple callback functions.
180
181
```typescript { .api }
182
/**
183
* Create a callback stack for managing multiple callbacks
184
* @returns Object with push, execute, and clear methods
185
*/
186
function createCallbackStack<A0 = void, A1 = void, A2 = void, A3 = void>(): {
187
push: (...callbacks: ((arg0: A0, arg1: A1, arg2: A2, arg3: A3) => void)[]) => void;
188
execute: (arg0: A0, arg1: A1, arg2: A2, arg3: A3) => void;
189
clear: VoidFunction;
190
};
191
192
/**
193
* Group synchronous function calls into microtasks
194
* @param fn - Function to group calls for
195
* @returns Grouped function
196
*/
197
function createMicrotask<A extends any[] | []>(fn: (...a: A) => void): (...a: A) => void;
198
```
199
200
**Usage Examples:**
201
202
```typescript
203
import { createCallbackStack, createMicrotask } from "@solid-primitives/utils";
204
205
// Callback stack
206
const stack = createCallbackStack<string>();
207
stack.push(
208
(msg) => console.log("First:", msg),
209
(msg) => console.log("Second:", msg)
210
);
211
stack.execute("Hello"); // Logs both messages and clears stack
212
213
// Microtask grouping
214
const logGrouped = createMicrotask((message: string) => {
215
console.log("Grouped:", message);
216
});
217
218
logGrouped("A");
219
logGrouped("B"); // Only the last call "B" will execute
220
```
221
222
### Array Utilities
223
224
Reactive-specific array manipulation and diffing utilities.
225
226
```typescript { .api }
227
/**
228
* Handle items removed and added to the array by diffing by reference
229
* @param current - New array instance
230
* @param prev - Previous array copy
231
* @param handleAdded - Called for every added item
232
* @param handleRemoved - Called for every removed item
233
*/
234
function handleDiffArray<T>(
235
current: readonly T[],
236
prev: readonly T[],
237
handleAdded: (item: T) => void,
238
handleRemoved: (item: T) => void
239
): void;
240
```
241
242
**Usage Examples:**
243
244
```typescript
245
import { createSignal, createEffect } from "solid-js";
246
import { handleDiffArray } from "@solid-primitives/utils";
247
248
const [items, setItems] = createSignal<string[]>([]);
249
let prevItems: string[] = [];
250
251
createEffect(() => {
252
const currentItems = items();
253
handleDiffArray(
254
currentItems,
255
prevItems,
256
(item) => console.log("Added:", item),
257
(item) => console.log("Removed:", item)
258
);
259
prevItems = [...currentItems];
260
});
261
```
262
263
## Types
264
265
```typescript { .api }
266
type MaybeAccessor<T> = T | Accessor<T>;
267
type MaybeAccessorValue<T extends MaybeAccessor<any>> = T extends () => any ? ReturnType<T> : T;
268
type OnAccessEffectFunction<S, Prev, Next extends Prev = Prev> = (
269
input: AccessReturnTypes<S>,
270
prevInput: AccessReturnTypes<S>,
271
v: Prev
272
) => Next;
273
type AccessReturnTypes<S> = S extends MaybeAccessor<any>[]
274
? { [I in keyof S]: AccessReturnTypes<S[I]>; }
275
: MaybeAccessorValue<S>;
276
```