0
# Hooks and Contexts
1
2
React hooks and context providers for accessing navigation state, dimensions, header information, and frame size tracking.
3
4
## Capabilities
5
6
### useHeaderHeight Hook
7
8
Hook to access the current header height from the HeaderHeightContext, useful for positioning content relative to the header.
9
10
```typescript { .api }
11
/**
12
* Hook to access current header height from context
13
* @returns Current header height in pixels
14
* @throws Error if used outside HeaderHeightContext provider
15
*/
16
function useHeaderHeight(): number;
17
```
18
19
**Usage Examples:**
20
21
```typescript
22
import { useHeaderHeight } from "@react-navigation/elements";
23
24
// Basic usage
25
function ContentWithHeaderOffset() {
26
const headerHeight = useHeaderHeight();
27
28
return (
29
<ScrollView
30
style={{ flex: 1 }}
31
contentInset={{ top: headerHeight }}
32
>
33
<Text>Content offset by header height</Text>
34
</ScrollView>
35
);
36
}
37
38
// Positioning floating elements
39
function FloatingActionButton() {
40
const headerHeight = useHeaderHeight();
41
42
return (
43
<View
44
style={{
45
position: 'absolute',
46
top: headerHeight + 20,
47
right: 20,
48
width: 56,
49
height: 56,
50
borderRadius: 28,
51
backgroundColor: '#007AFF'
52
}}
53
>
54
<Icon name="plus" color="white" />
55
</View>
56
);
57
}
58
59
// Conditional layout based on header height
60
function AdaptiveLayout() {
61
const headerHeight = useHeaderHeight();
62
const isCompactHeader = headerHeight < 100;
63
64
return (
65
<View style={{ flex: 1, paddingTop: headerHeight }}>
66
{isCompactHeader ? (
67
<CompactLayout />
68
) : (
69
<ExpandedLayout />
70
)}
71
</View>
72
);
73
}
74
```
75
76
### useFrameSize Hook
77
78
Hook for tracking frame size changes with optional throttling, providing current dimensions and selector-based updates.
79
80
```typescript { .api }
81
/**
82
* Hook for tracking frame size with optional throttling
83
* @param selector - Function to select specific values from frame
84
* @param throttle - Whether to throttle frame updates (default: false)
85
* @returns Selected value from current frame dimensions
86
*/
87
function useFrameSize<T>(
88
selector: (frame: Frame) => T,
89
throttle?: boolean
90
): T;
91
92
interface Frame {
93
width: number;
94
height: number;
95
}
96
```
97
98
**Usage Examples:**
99
100
```typescript
101
import { useFrameSize } from "@react-navigation/elements";
102
103
// Get current frame width
104
function ResponsiveComponent() {
105
const width = useFrameSize(frame => frame.width);
106
107
return (
108
<View style={{
109
flexDirection: width > 768 ? 'row' : 'column'
110
}}>
111
<Text>Responsive layout based on width: {width}px</Text>
112
</View>
113
);
114
}
115
116
// Get both width and height
117
function FullFrameInfo() {
118
const dimensions = useFrameSize(frame => ({
119
width: frame.width,
120
height: frame.height,
121
aspectRatio: frame.width / frame.height
122
}));
123
124
return (
125
<View>
126
<Text>Width: {dimensions.width}px</Text>
127
<Text>Height: {dimensions.height}px</Text>
128
<Text>Aspect Ratio: {dimensions.aspectRatio.toFixed(2)}</Text>
129
</View>
130
);
131
}
132
133
// Throttled updates for performance
134
function ThrottledFrameSize() {
135
const width = useFrameSize(
136
frame => frame.width,
137
true // Throttle updates
138
);
139
140
return (
141
<Text>
142
Throttled width updates: {width}px
143
</Text>
144
);
145
}
146
147
// Conditional rendering based on frame size
148
function AdaptiveContent() {
149
const isLandscape = useFrameSize(
150
frame => frame.width > frame.height
151
);
152
153
return (
154
<View style={{ flex: 1 }}>
155
{isLandscape ? (
156
<LandscapeLayout />
157
) : (
158
<PortraitLayout />
159
)}
160
</View>
161
);
162
}
163
```
164
165
## Context Components
166
167
### FrameSizeProvider
168
169
Provider component that enables frame size tracking for `useFrameSize` hook by monitoring and providing device dimensions.
170
171
```typescript { .api }
172
/**
173
* Provider for frame size tracking context
174
* @param initialFrame - Initial frame dimensions
175
* @param children - Child components that will have access to frame size
176
* @param style - Optional style for the provider container
177
*/
178
function FrameSizeProvider(props: {
179
initialFrame: Frame;
180
children: React.ReactNode;
181
style?: StyleProp<ViewStyle>;
182
}): React.ReactElement;
183
184
interface Frame {
185
width: number;
186
height: number;
187
}
188
```
189
190
**Usage Examples:**
191
192
```typescript
193
import { FrameSizeProvider, useFrameSize } from "@react-navigation/elements";
194
195
// Basic provider setup
196
function App() {
197
const initialFrame = { width: 375, height: 812 }; // iPhone dimensions
198
199
return (
200
<FrameSizeProvider initialFrame={initialFrame}>
201
<ResponsiveApp />
202
</FrameSizeProvider>
203
);
204
}
205
206
// Nested providers automatically avoid double-wrapping
207
function NestedProviders({ children }) {
208
const frame1 = { width: 768, height: 1024 };
209
const frame2 = { width: 1024, height: 768 };
210
211
return (
212
<FrameSizeProvider initialFrame={frame1}>
213
<FrameSizeProvider initialFrame={frame2}>
214
{children} {/* Only one provider is active */}
215
</FrameSizeProvider>
216
</FrameSizeProvider>
217
);
218
}
219
220
// Using with safe area frame
221
import { useSafeAreaFrame } from 'react-native-safe-area-context';
222
223
function SafeAreaFrameProvider({ children }) {
224
const safeAreaFrame = useSafeAreaFrame();
225
226
return (
227
<FrameSizeProvider initialFrame={safeAreaFrame}>
228
{children}
229
</FrameSizeProvider>
230
);
231
}
232
```
233
234
### HeaderBackContext
235
236
Context providing back button state and navigation information for header components.
237
238
```typescript { .api }
239
/**
240
* Context for back button state and navigation info
241
* @type React context providing back button configuration or undefined
242
*/
243
const HeaderBackContext: React.Context<{
244
/** Back button title (usually previous screen title) */
245
title: string | undefined;
246
/** Back button href for web navigation */
247
href: string | undefined;
248
} | undefined>;
249
```
250
251
**Usage Examples:**
252
253
```typescript
254
import { HeaderBackContext } from "@react-navigation/elements";
255
import { useContext } from "react";
256
257
// Accessing back context
258
function CustomHeaderComponent() {
259
const backContext = useContext(HeaderBackContext);
260
261
return (
262
<View>
263
{backContext && (
264
<Text>Back to: {backContext.title || 'Previous Screen'}</Text>
265
)}
266
</View>
267
);
268
}
269
270
// Providing back context
271
<HeaderBackContext.Provider value={{ title: "Settings", href: undefined }}>
272
<HeaderContent />
273
</HeaderBackContext.Provider>
274
```
275
276
### HeaderHeightContext
277
278
Context providing the current header height for layout calculations and positioning.
279
280
```typescript { .api }
281
/**
282
* Context for current header height
283
* @type React context providing header height in pixels or undefined
284
*/
285
const HeaderHeightContext: React.Context<number | undefined>;
286
```
287
288
**Usage Examples:**
289
290
```typescript
291
import { HeaderHeightContext } from "@react-navigation/elements";
292
import { useContext } from "react";
293
294
// Manual context access (prefer useHeaderHeight hook)
295
function ManualHeaderHeight() {
296
const headerHeight = useContext(HeaderHeightContext);
297
298
return (
299
<View style={{ paddingTop: headerHeight || 0 }}>
300
<Text>Content with header padding</Text>
301
</View>
302
);
303
}
304
305
// Providing header height context
306
<HeaderHeightContext.Provider value={88}>
307
<ScreenContent />
308
</HeaderHeightContext.Provider>
309
```
310
311
### HeaderShownContext
312
313
Context indicating whether the header is currently shown, useful for layout adjustments.
314
315
```typescript { .api }
316
/**
317
* Context for header visibility state
318
* @type React context providing boolean indicating if header is shown
319
*/
320
const HeaderShownContext: React.Context<boolean>;
321
```
322
323
**Usage Examples:**
324
325
```typescript
326
import { HeaderShownContext } from "@react-navigation/elements";
327
import { useContext } from "react";
328
329
// Accessing header shown state
330
function ConditionalContent() {
331
const isHeaderShown = useContext(HeaderShownContext);
332
333
return (
334
<View style={{
335
paddingTop: isHeaderShown ? 0 : 20
336
}}>
337
<Text>
338
Header is {isHeaderShown ? 'shown' : 'hidden'}
339
</Text>
340
</View>
341
);
342
}
343
344
// Providing header shown context
345
<HeaderShownContext.Provider value={true}>
346
<ScreenWithHeader />
347
</HeaderShownContext.Provider>
348
349
// Combined with other contexts
350
function FullHeaderContext({ children, headerHeight, isShown, backInfo }) {
351
return (
352
<HeaderHeightContext.Provider value={headerHeight}>
353
<HeaderShownContext.Provider value={isShown}>
354
<HeaderBackContext.Provider value={backInfo}>
355
{children}
356
</HeaderBackContext.Provider>
357
</HeaderShownContext.Provider>
358
</HeaderHeightContext.Provider>
359
);
360
}
361
```
362
363
## Advanced Usage Patterns
364
365
### Responsive Layout Hook
366
367
Combine useFrameSize with breakpoints for responsive design:
368
369
```typescript
370
function useResponsiveLayout() {
371
return useFrameSize(frame => {
372
const { width } = frame;
373
374
if (width < 480) return 'mobile';
375
if (width < 768) return 'tablet';
376
if (width < 1024) return 'desktop';
377
return 'large';
378
});
379
}
380
381
function ResponsiveComponent() {
382
const layout = useResponsiveLayout();
383
384
const styles = {
385
mobile: { padding: 16, fontSize: 14 },
386
tablet: { padding: 24, fontSize: 16 },
387
desktop: { padding: 32, fontSize: 18 },
388
large: { padding: 40, fontSize: 20 }
389
};
390
391
return (
392
<View style={styles[layout]}>
393
<Text>Layout: {layout}</Text>
394
</View>
395
);
396
}
397
```
398
399
### Header-Aware Scrolling
400
401
Combine header height with scroll views for proper content positioning:
402
403
```typescript
404
function HeaderAwareScrollView({ children }) {
405
const headerHeight = useHeaderHeight();
406
const isHeaderShown = useContext(HeaderShownContext);
407
408
return (
409
<ScrollView
410
style={{ flex: 1 }}
411
contentContainerStyle={{
412
paddingTop: isHeaderShown ? headerHeight : 0
413
}}
414
scrollIndicatorInsets={{
415
top: isHeaderShown ? headerHeight : 0
416
}}
417
>
418
{children}
419
</ScrollView>
420
);
421
}
422
```
423
424
### Performance Monitoring
425
426
Use frame size changes to monitor performance:
427
428
```typescript
429
function PerformanceMonitor() {
430
const frameChanges = useRef(0);
431
432
useFrameSize(frame => {
433
frameChanges.current += 1;
434
console.log(`Frame changed ${frameChanges.current} times:`, frame);
435
return frame;
436
});
437
438
return null; // This is just for monitoring
439
}
440
```
441
442
## Context Error Handling
443
444
The hooks include proper error handling when used outside their providers:
445
446
```typescript
447
// useHeaderHeight will throw if used outside HeaderHeightContext
448
function ComponentWithErrorHandling() {
449
try {
450
const headerHeight = useHeaderHeight();
451
return <Text>Header height: {headerHeight}</Text>;
452
} catch (error) {
453
return <Text>No header context available</Text>;
454
}
455
}
456
```
457
458
## Platform Considerations
459
460
### Web
461
- **ResizeObserver**: Uses ResizeObserver API for efficient frame size tracking
462
- **CSS Layout**: Frame size updates coordinate with CSS layout changes
463
- **Performance**: Throttled updates prevent excessive re-renders during window resize
464
465
### Mobile (iOS/Android)
466
- **Orientation Changes**: Automatically handles device orientation changes
467
- **Safe Area**: Frame size accounts for safe area insets
468
- **Keyboard**: Frame updates when software keyboard appears/disappears