0
# Hooks
1
2
Complete React hooks implementation for state management and side effects in functional components. All hooks are compatible with React hooks and follow the same rules and behavior patterns.
3
4
## Capabilities
5
6
### State Hook
7
8
Manages local state in functional components. Returns current state value and setter function.
9
10
```javascript { .api }
11
/**
12
* Manages local state in functional components
13
* @param initialState - Initial state value or function returning initial state
14
* @returns Array containing [currentState, setStateFunction]
15
*/
16
function useState(initialState);
17
```
18
19
**Usage Examples:**
20
21
```javascript
22
import { createElement, useState } from 'rax';
23
24
function Counter() {
25
const [count, setCount] = useState(0);
26
const [name, setName] = useState('');
27
28
// With function initializer (for expensive computations)
29
const [expensiveValue, setExpensiveValue] = useState(() => {
30
return computeExpensiveValue();
31
});
32
33
const increment = () => setCount(count + 1);
34
const decrement = () => setCount(prevCount => prevCount - 1);
35
36
return createElement('div', null,
37
createElement('p', null, `Count: ${count}`),
38
createElement('input', {
39
value: name,
40
onChange: (e) => setName(e.target.value),
41
placeholder: 'Enter name'
42
}),
43
createElement('button', { onClick: increment }, '+'),
44
createElement('button', { onClick: decrement }, '-')
45
);
46
}
47
```
48
49
### Effect Hook
50
51
Performs side effects in functional components. Equivalent to componentDidMount, componentDidUpdate, and componentWillUnmount combined.
52
53
```javascript { .api }
54
/**
55
* Performs side effects in functional components (deferred execution)
56
* @param effect - Effect function, can return cleanup function
57
* @param inputs - Optional dependency array for effect optimization
58
*/
59
function useEffect(effect, inputs);
60
```
61
62
**Usage Examples:**
63
64
```javascript
65
import { createElement, useState, useEffect } from 'rax';
66
67
function DataFetcher({ userId }) {
68
const [user, setUser] = useState(null);
69
const [loading, setLoading] = useState(true);
70
71
// Effect with cleanup
72
useEffect(() => {
73
let cancelled = false;
74
75
async function fetchUser() {
76
try {
77
const response = await fetch(`/api/users/${userId}`);
78
const userData = await response.json();
79
if (!cancelled) {
80
setUser(userData);
81
setLoading(false);
82
}
83
} catch (error) {
84
if (!cancelled) {
85
console.error('Failed to fetch user:', error);
86
setLoading(false);
87
}
88
}
89
}
90
91
fetchUser();
92
93
// Cleanup function
94
return () => {
95
cancelled = true;
96
};
97
}, [userId]); // Re-run when userId changes
98
99
// Effect without dependencies (runs after every render)
100
useEffect(() => {
101
document.title = user ? `User: ${user.name}` : 'Loading...';
102
});
103
104
// Effect with empty dependencies (runs once on mount)
105
useEffect(() => {
106
console.log('Component mounted');
107
return () => console.log('Component unmounting');
108
}, []);
109
110
if (loading) {
111
return createElement('div', null, 'Loading user...');
112
}
113
114
return createElement('div', null,
115
createElement('h1', null, user.name),
116
createElement('p', null, user.email)
117
);
118
}
119
```
120
121
### Layout Effect Hook
122
123
Synchronous version of useEffect that fires before the browser paints. Use for DOM measurements and synchronous DOM mutations.
124
125
```javascript { .api }
126
/**
127
* Synchronous version of useEffect that fires before browser paint
128
* @param effect - Effect function, can return cleanup function
129
* @param inputs - Optional dependency array for effect optimization
130
*/
131
function useLayoutEffect(effect, inputs);
132
```
133
134
### Context Hook
135
136
Consumes context values from the nearest Provider component.
137
138
```javascript { .api }
139
/**
140
* Consumes context value from nearest Provider
141
* @param context - Context object created by createContext
142
* @returns Current context value
143
*/
144
function useContext(context);
145
```
146
147
**Usage Examples:**
148
149
```javascript
150
import { createElement, createContext, useContext, useState } from 'rax';
151
152
// Create context
153
const ThemeContext = createContext('light');
154
155
function App() {
156
const [theme, setTheme] = useState('light');
157
158
return createElement(ThemeContext.Provider, { value: theme },
159
createElement('div', null,
160
createElement(ThemeToggle, { onToggle: () => setTheme(theme === 'light' ? 'dark' : 'light') }),
161
createElement(ThemedButton)
162
)
163
);
164
}
165
166
function ThemedButton() {
167
const theme = useContext(ThemeContext);
168
169
return createElement('button', {
170
style: {
171
backgroundColor: theme === 'light' ? '#fff' : '#333',
172
color: theme === 'light' ? '#333' : '#fff'
173
}
174
}, `I'm ${theme} themed!`);
175
}
176
```
177
178
### Ref Hook
179
180
Creates a mutable ref object that persists across renders.
181
182
```javascript { .api }
183
/**
184
* Creates a mutable ref object that persists across renders
185
* @param initialValue - Initial value for the ref
186
* @returns RefObject with current property
187
*/
188
function useRef(initialValue);
189
```
190
191
**Usage Examples:**
192
193
```javascript
194
import { createElement, useRef, useEffect } from 'rax';
195
196
function FocusInput() {
197
const inputRef = useRef(null);
198
199
useEffect(() => {
200
// Focus input on mount
201
if (inputRef.current) {
202
inputRef.current.focus();
203
}
204
}, []);
205
206
const focusInput = () => {
207
if (inputRef.current) {
208
inputRef.current.focus();
209
}
210
};
211
212
return createElement('div', null,
213
createElement('input', { ref: inputRef, type: 'text' }),
214
createElement('button', { onClick: focusInput }, 'Focus Input')
215
);
216
}
217
```
218
219
### Callback Hook
220
221
Memoizes callback functions to prevent unnecessary re-renders of child components.
222
223
```javascript { .api }
224
/**
225
* Memoizes callback functions based on dependencies
226
* @param callback - Function to memoize
227
* @param inputs - Dependency array for memoization
228
* @returns Memoized callback function
229
*/
230
function useCallback(callback, inputs);
231
```
232
233
### Memo Hook
234
235
Memoizes computed values to avoid expensive calculations on every render.
236
237
```javascript { .api }
238
/**
239
* Memoizes computed values based on dependencies
240
* @param create - Function that returns the value to memoize
241
* @param inputs - Dependency array for memoization
242
* @returns Memoized value
243
*/
244
function useMemo(create, inputs);
245
```
246
247
**Usage Examples:**
248
249
```javascript
250
import { createElement, useState, useCallback, useMemo } from 'rax';
251
252
function ExpensiveCalculator({ items }) {
253
const [filter, setFilter] = useState('');
254
255
// Memoize expensive calculation
256
const expensiveValue = useMemo(() => {
257
console.log('Calculating expensive value...');
258
return items.reduce((sum, item) => sum + item.value, 0);
259
}, [items]);
260
261
// Memoize callback to prevent child re-renders
262
const handleFilterChange = useCallback((e) => {
263
setFilter(e.target.value);
264
}, []);
265
266
const filteredItems = useMemo(() => {
267
return items.filter(item =>
268
item.name.toLowerCase().includes(filter.toLowerCase())
269
);
270
}, [items, filter]);
271
272
return createElement('div', null,
273
createElement('input', {
274
value: filter,
275
onChange: handleFilterChange,
276
placeholder: 'Filter items...'
277
}),
278
createElement('p', null, `Total value: ${expensiveValue}`),
279
createElement('p', null, `Filtered items: ${filteredItems.length}`)
280
);
281
}
282
```
283
284
### Reducer Hook
285
286
Manages complex state logic with a reducer function, similar to Redux.
287
288
```javascript { .api }
289
/**
290
* Manages state with a reducer function
291
* @param reducer - Reducer function (state, action) => newState
292
* @param initialArg - Initial state or argument for init function
293
* @param init - Optional function to compute initial state
294
* @returns Array containing [currentState, dispatchFunction]
295
*/
296
function useReducer(reducer, initialArg, init);
297
```
298
299
**Usage Examples:**
300
301
```javascript
302
import { createElement, useReducer } from 'rax';
303
304
// Reducer function
305
function counterReducer(state, action) {
306
switch (action.type) {
307
case 'increment':
308
return { count: state.count + 1 };
309
case 'decrement':
310
return { count: state.count - 1 };
311
case 'reset':
312
return { count: 0 };
313
default:
314
return state;
315
}
316
}
317
318
function Counter() {
319
const [state, dispatch] = useReducer(counterReducer, { count: 0 });
320
321
return createElement('div', null,
322
createElement('p', null, `Count: ${state.count}`),
323
createElement('button', {
324
onClick: () => dispatch({ type: 'increment' })
325
}, '+'),
326
createElement('button', {
327
onClick: () => dispatch({ type: 'decrement' })
328
}, '-'),
329
createElement('button', {
330
onClick: () => dispatch({ type: 'reset' })
331
}, 'Reset')
332
);
333
}
334
```
335
336
### Imperative Handle Hook
337
338
Customizes the instance value exposed by a ref when using forwardRef.
339
340
```javascript { .api }
341
/**
342
* Customizes the instance value exposed by a ref
343
* @param ref - Ref object to customize
344
* @param create - Function that returns the instance value
345
* @param inputs - Optional dependency array
346
*/
347
function useImperativeHandle(ref, create, inputs);
348
```
349
350
**Usage Examples:**
351
352
```javascript
353
import { createElement, forwardRef, useImperativeHandle, useRef } from 'rax';
354
355
const FancyInput = forwardRef((props, ref) => {
356
const inputRef = useRef();
357
358
useImperativeHandle(ref, () => ({
359
focus() {
360
inputRef.current.focus();
361
},
362
scrollIntoView() {
363
inputRef.current.scrollIntoView();
364
},
365
getValue() {
366
return inputRef.current.value;
367
}
368
}), []);
369
370
return createElement('input', { ref: inputRef, ...props });
371
});
372
373
function App() {
374
const fancyInputRef = useRef();
375
376
const handleFocus = () => {
377
fancyInputRef.current.focus();
378
};
379
380
const handleGetValue = () => {
381
alert(fancyInputRef.current.getValue());
382
};
383
384
return createElement('div', null,
385
createElement(FancyInput, { ref: fancyInputRef }),
386
createElement('button', { onClick: handleFocus }, 'Focus'),
387
createElement('button', { onClick: handleGetValue }, 'Get Value')
388
);
389
}
390
```
391
392
## Hook Rules
393
394
All Rax hooks follow the same rules as React hooks:
395
396
1. **Only call hooks at the top level** - Don't call hooks inside loops, conditions, or nested functions
397
2. **Only call hooks from Rax functions** - Call hooks from functional components or custom hooks
398
3. **Hooks must be called in the same order** - Don't call hooks conditionally
399
400
## Types
401
402
```javascript { .api }
403
// State hook types
404
type StateUpdater<S> = (prevState: S) => S;
405
type SetStateAction<S> = S | StateUpdater<S>;
406
type StateSetter<S> = (value: SetStateAction<S>) => void;
407
408
// Effect hook types
409
type EffectCallback = () => (void | (() => void));
410
type DependencyList = ReadonlyArray<any>;
411
412
// Reducer hook types
413
type Reducer<S, A> = (prevState: S, action: A) => S;
414
type ReducerState<R> = R extends Reducer<infer S, any> ? S : never;
415
type ReducerAction<R> = R extends Reducer<any, infer A> ? A : never;
416
type Dispatch<A> = (value: A) => void;
417
418
// Ref hook types
419
interface MutableRefObject<T> {
420
current: T;
421
}
422
423
// Callback and memo hook types
424
type CallbackFunction = (...args: any[]) => any;
425
type MemoFactory<T> = () => T;
426
427
// Context hook types
428
interface Context<T> {
429
Provider: ComponentType<{ value: T; children?: any }>;
430
Consumer: ComponentType<{ children: (value: T) => any }>;
431
_contextID: string;
432
_defaultValue: T;
433
}
434
```