0
# Hook Rendering
1
2
Core functionality for rendering and testing React hooks in isolation, providing a test harness that runs hooks within a proper React component context.
3
4
## Capabilities
5
6
### renderHook Function
7
8
Creates a test harness for running React hooks in isolation, returning a result container and utilities for interacting with the hook.
9
10
```typescript { .api }
11
/**
12
* Renders a React hook in a test environment
13
* @param callback - Function that calls the hook to be tested
14
* @param options - Optional configuration including initial props and wrapper component
15
* @returns RenderHookResult with current value, utilities, and async helpers
16
*/
17
function renderHook<TProps, TResult>(
18
callback: (props: TProps) => TResult,
19
options?: RenderHookOptions<TProps>
20
): RenderHookResult<TProps, TResult>;
21
22
interface RenderHookOptions<TProps> {
23
/** Initial props to pass to the hook callback */
24
initialProps?: TProps;
25
/** React component to wrap the hook (for context providers, etc.) */
26
wrapper?: React.ComponentType<TProps>;
27
}
28
29
interface RenderHookResult<TProps, TValue> {
30
/** Container holding the hook's return value and history */
31
result: RenderResult<TValue>;
32
/** Re-render the hook with new props */
33
rerender: (newProps?: TProps) => void;
34
/** Unmount the hook and cleanup resources */
35
unmount: () => void;
36
/** Wait for a condition to be true */
37
waitFor: (callback: () => boolean | void, options?: WaitForOptions) => Promise<void>;
38
/** Wait for a selected value to change */
39
waitForValueToChange: (selector: () => unknown, options?: WaitForValueToChangeOptions) => Promise<void>;
40
/** Wait for the next hook update */
41
waitForNextUpdate: (options?: WaitForNextUpdateOptions) => Promise<void>;
42
}
43
44
interface RenderResult<TValue> {
45
/** Current return value of the hook */
46
readonly current: TValue;
47
/** Array of all values returned by the hook (including errors) */
48
readonly all: Array<TValue | Error>;
49
/** Current error if the hook threw an error */
50
readonly error?: Error;
51
}
52
```
53
54
**Usage Examples:**
55
56
```typescript
57
import { renderHook } from "@testing-library/react-hooks";
58
import { useState } from "react";
59
60
// Simple hook test
61
test("renders hook without props", () => {
62
const { result } = renderHook(() => useState(0));
63
64
expect(result.current[0]).toBe(0);
65
expect(typeof result.current[1]).toBe("function");
66
});
67
68
// Hook with initial props
69
function useCounter(initialCount: number) {
70
const [count, setCount] = useState(initialCount);
71
return { count, increment: () => setCount(c => c + 1) };
72
}
73
74
test("renders hook with initial props", () => {
75
const { result } = renderHook(() => useCounter(5));
76
77
expect(result.current.count).toBe(5);
78
});
79
80
// Hook with wrapper component (for context)
81
const ThemeContext = React.createContext("light");
82
83
function useTheme() {
84
return React.useContext(ThemeContext);
85
}
86
87
test("renders hook with wrapper", () => {
88
const wrapper = ({ children }) => (
89
<ThemeContext.Provider value="dark">{children}</ThemeContext.Provider>
90
);
91
92
const { result } = renderHook(() => useTheme(), { wrapper });
93
94
expect(result.current).toBe("dark");
95
});
96
```
97
98
### Rerender Hook
99
100
Re-renders the hook with new props, useful for testing how hooks respond to prop changes.
101
102
```typescript { .api }
103
/**
104
* Re-render the hook with new props
105
* @param newProps - New props to pass to the hook callback (optional)
106
*/
107
rerender(newProps?: TProps): void;
108
```
109
110
**Usage Examples:**
111
112
```typescript
113
function useGreeting(name: string) {
114
return `Hello, ${name}!`;
115
}
116
117
test("hook responds to prop changes", () => {
118
const { result, rerender } = renderHook(
119
(props) => useGreeting(props.name),
120
{ initialProps: { name: "Alice" } }
121
);
122
123
expect(result.current).toBe("Hello, Alice!");
124
125
// Re-render with new props
126
rerender({ name: "Bob" });
127
128
expect(result.current).toBe("Hello, Bob!");
129
});
130
```
131
132
### Unmount Hook
133
134
Unmounts the hook and cleans up any associated resources.
135
136
```typescript { .api }
137
/**
138
* Unmount the hook and cleanup resources
139
*/
140
unmount(): void;
141
```
142
143
**Usage Examples:**
144
145
```typescript
146
function useInterval(callback: () => void, delay: number) {
147
React.useEffect(() => {
148
const interval = setInterval(callback, delay);
149
return () => clearInterval(interval);
150
}, [callback, delay]);
151
}
152
153
test("hook cleans up on unmount", () => {
154
const callback = jest.fn();
155
const { unmount } = renderHook(() => useInterval(callback, 100));
156
157
// Let some time pass
158
jest.advanceTimersByTime(250);
159
expect(callback).toHaveBeenCalledTimes(2);
160
161
// Unmount and verify cleanup
162
unmount();
163
jest.advanceTimersByTime(200);
164
expect(callback).toHaveBeenCalledTimes(2); // No more calls
165
});
166
```
167
168
### Result History
169
170
Access to the complete history of hook return values and errors.
171
172
```typescript { .api }
173
interface RenderResult<TValue> {
174
/** Current return value of the hook */
175
readonly current: TValue;
176
/** Array of all values returned by the hook throughout its lifecycle */
177
readonly all: Array<TValue | Error>;
178
/** Current error if the hook is in an error state */
179
readonly error?: Error;
180
}
181
```
182
183
**Usage Examples:**
184
185
```typescript
186
function useToggle(initial = false) {
187
const [value, setValue] = useState(initial);
188
const toggle = () => setValue(prev => !prev);
189
return { value, toggle };
190
}
191
192
test("tracks hook result history", () => {
193
const { result } = renderHook(() => useToggle(false));
194
195
expect(result.current.value).toBe(false);
196
expect(result.all).toHaveLength(1);
197
expect(result.all[0]).toEqual({ value: false, toggle: expect.any(Function) });
198
199
act(() => {
200
result.current.toggle();
201
});
202
203
expect(result.current.value).toBe(true);
204
expect(result.all).toHaveLength(2);
205
expect(result.all[1]).toEqual({ value: true, toggle: expect.any(Function) });
206
});
207
```