0
# Children Utilities
1
2
Complete React.Children API implementation for working with component children, providing utilities for iteration, counting, and manipulation of child elements.
3
4
## Capabilities
5
6
### Children.map Function
7
8
Maps over children with optional context binding and type safety.
9
10
```typescript { .api }
11
/**
12
* Maps over children array with optional context binding
13
* @param children - Array of child elements to map over
14
* @param fn - Function to apply to each child
15
* @param ctx - Optional context to bind the function to
16
* @returns Array of mapped results
17
*/
18
map<T, U>(
19
children: T[],
20
fn: (child: T, index: number) => U,
21
ctx?: any
22
): U[];
23
```
24
25
**Usage Examples:**
26
27
```typescript
28
import { Children, createElement } from "inferno-compat";
29
30
function ButtonGroup({ children }) {
31
// Add click handlers to all child buttons
32
const enhancedChildren = Children.map(children, (child, index) => {
33
if (child.type === 'button') {
34
return cloneElement(child, {
35
onClick: () => console.log(`Button ${index} clicked`),
36
key: index
37
});
38
}
39
return child;
40
});
41
42
return createElement('div', { className: 'button-group' }, enhancedChildren);
43
}
44
45
// With context binding
46
function ListRenderer({ children, formatter }) {
47
const formattedChildren = Children.map(
48
children,
49
function(child, index) {
50
return this.formatChild(child, index);
51
},
52
formatter // Context object with formatChild method
53
);
54
55
return createElement('ul', null, formattedChildren);
56
}
57
58
// Handling null/undefined children
59
function SafeMap({ children }) {
60
// Children.map gracefully handles null/undefined
61
const mapped = Children.map(children, (child, index) => {
62
return createElement('li', { key: index }, child);
63
});
64
65
return createElement('ul', null, mapped || []);
66
}
67
```
68
69
### Children.forEach Function
70
71
Iterates over children with side effects, similar to Array.prototype.forEach.
72
73
```typescript { .api }
74
/**
75
* Iterates over children array with optional context binding
76
* @param children - Array of child elements to iterate over
77
* @param fn - Function to call for each child
78
* @param ctx - Optional context to bind the function to
79
*/
80
forEach<T>(
81
children: T[],
82
fn: (child: T, index: number) => void,
83
ctx?: any
84
): void;
85
```
86
87
**Usage Examples:**
88
89
```typescript
90
import { Children, createElement, Component } from "inferno-compat";
91
92
class FormValidator extends Component {
93
constructor(props) {
94
super(props);
95
this.state = { errors: [] };
96
}
97
98
validateChildren = () => {
99
const errors = [];
100
101
Children.forEach(this.props.children, (child, index) => {
102
if (child.type === 'input' && child.props.required && !child.props.value) {
103
errors.push(`Field ${index + 1} is required`);
104
}
105
});
106
107
this.setState({ errors });
108
}
109
110
render() {
111
const { children } = this.props;
112
const { errors } = this.state;
113
114
return createElement('form', null,
115
children,
116
errors.length > 0 && createElement('div', { className: 'errors' },
117
errors.map((error, index) =>
118
createElement('p', { key: index }, error)
119
)
120
)
121
);
122
}
123
}
124
125
// Context usage for method binding
126
class ComponentInspector extends Component {
127
inspectChild(child, index) {
128
console.log(`Child ${index}:`, {
129
type: child.type,
130
props: Object.keys(child.props || {}),
131
hasChildren: !!child.children
132
});
133
}
134
135
componentDidMount() {
136
Children.forEach(
137
this.props.children,
138
this.inspectChild,
139
this // Bind to component instance
140
);
141
}
142
143
render() {
144
return createElement('div', null, this.props.children);
145
}
146
}
147
```
148
149
### Children.count Function
150
151
Counts the number of children in a children array.
152
153
```typescript { .api }
154
/**
155
* Returns the number of children in a children array
156
* @param children - Array of child elements to count
157
* @returns Number of children in the array
158
*/
159
count(children: any[]): number;
160
```
161
162
**Usage Examples:**
163
164
```typescript
165
import { Children, createElement } from "inferno-compat";
166
167
function TabContainer({ children, activeTab = 0 }) {
168
const childCount = Children.count(children);
169
170
return createElement('div', { className: 'tab-container' },
171
// Tab headers
172
createElement('div', { className: 'tab-headers' },
173
Array.from({ length: childCount }, (_, index) =>
174
createElement('button', {
175
key: index,
176
className: index === activeTab ? 'active' : '',
177
onClick: () => setActiveTab(index)
178
}, `Tab ${index + 1}`)
179
)
180
),
181
// Active tab content
182
Children.toArray(children)[activeTab]
183
);
184
}
185
186
function ConditionalRenderer({ children, maxChildren = 5 }) {
187
const count = Children.count(children);
188
189
if (count === 0) {
190
return createElement('p', null, 'No content available');
191
}
192
193
if (count > maxChildren) {
194
return createElement('div', null,
195
createElement('p', null, `Showing first ${maxChildren} of ${count} items`),
196
Children.toArray(children).slice(0, maxChildren)
197
);
198
}
199
200
return createElement('div', null, children);
201
}
202
203
// Edge cases handling
204
function SafeCounter({ children }) {
205
const count = Children.count(children); // Handles null/undefined gracefully
206
207
return createElement('div', null,
208
createElement('p', null, `Child count: ${count}`),
209
children
210
);
211
}
212
```
213
214
### Children.only Function
215
216
Returns the only child, throwing an error if there are zero or multiple children.
217
218
```typescript { .api }
219
/**
220
* Returns the single child element, throws error if not exactly one child
221
* @param children - Children array that should contain exactly one element
222
* @returns The single child element
223
* @throws Error if children count is not exactly 1
224
*/
225
only(children: any[]): any;
226
```
227
228
**Usage Examples:**
229
230
```typescript
231
import { Children, createElement, cloneElement } from "inferno-compat";
232
233
function SingleChildWrapper({ children, className }) {
234
// Ensure exactly one child is provided
235
const child = Children.only(children);
236
237
// Add wrapper class to the single child
238
return cloneElement(child, {
239
className: `${child.props.className || ''} ${className}`.trim()
240
});
241
}
242
243
// Usage - this works
244
const wrapped = createElement(SingleChildWrapper, { className: 'highlight' },
245
createElement('p', null, 'Single paragraph')
246
);
247
248
// This would throw an error - multiple children
249
try {
250
const invalid = createElement(SingleChildWrapper, { className: 'highlight' },
251
createElement('p', null, 'First paragraph'),
252
createElement('p', null, 'Second paragraph')
253
);
254
} catch (error) {
255
console.error(error.message); // "Children.only() expects only one child."
256
}
257
258
function ModalContent({ children }) {
259
try {
260
const content = Children.only(children);
261
return createElement('div', { className: 'modal-content' }, content);
262
} catch (error) {
263
return createElement('div', { className: 'modal-error' },
264
createElement('p', null, 'Modal requires exactly one child element')
265
);
266
}
267
}
268
269
// Higher-order component that requires single child
270
function withEnhancement(WrappedComponent) {
271
return function EnhancedComponent(props) {
272
return createElement(WrappedComponent, {
273
...props,
274
children: Children.only(props.children) // Ensure single child
275
});
276
};
277
}
278
```
279
280
### Children.toArray Function
281
282
Converts children to a flattened array, handling nested structures and various input types.
283
284
```typescript { .api }
285
/**
286
* Converts children to a flattened array
287
* @param children - Children to convert (can be arrays, single elements, null, etc.)
288
* @returns Flattened array of children
289
*/
290
toArray(children: any[]): any[];
291
```
292
293
**Usage Examples:**
294
295
```typescript
296
import { Children, createElement } from "inferno-compat";
297
298
function FlexibleList({ children }) {
299
const childArray = Children.toArray(children);
300
301
return createElement('ul', null,
302
childArray.map((child, index) =>
303
createElement('li', { key: index }, child)
304
)
305
);
306
}
307
308
// Handles various input types
309
const list = createElement(FlexibleList, null,
310
'Simple string',
311
createElement('span', null, 'Element'),
312
['Nested', 'Array'],
313
null, // Ignored
314
undefined, // Ignored
315
42 // Number
316
);
317
318
function NavigationBreadcrumbs({ children }) {
319
const items = Children.toArray(children);
320
321
return createElement('nav', { className: 'breadcrumbs' },
322
items.map((item, index) =>
323
createElement('span', { key: index },
324
item,
325
index < items.length - 1 &&
326
createElement('span', { className: 'separator' }, ' > ')
327
)
328
)
329
);
330
}
331
332
// Complex nesting example
333
function DeepNestingHandler({ children }) {
334
const flattened = Children.toArray(children);
335
336
console.log('Original structure:', children);
337
console.log('Flattened array:', flattened);
338
339
return createElement('div', null, flattened);
340
}
341
342
const complex = createElement(DeepNestingHandler, null,
343
[
344
['deeply', 'nested'],
345
'array',
346
[['structure'], 'here']
347
]
348
);
349
// Results in: ['deeply', 'nested', 'array', 'structure', 'here']
350
```
351
352
### Children Object Interface
353
354
The complete Children utility object with all methods:
355
356
```typescript { .api }
357
interface Children {
358
map<T, U>(children: T[], fn: (child: T, index: number) => U, ctx?: any): U[];
359
forEach<T>(children: T[], fn: (child: T, index: number) => void, ctx?: any): void;
360
count(children: any[]): number;
361
only(children: any[]): any;
362
toArray(children: any[]): any[];
363
}
364
```
365
366
### React Compatibility Features
367
368
The Children utilities provide full React compatibility including:
369
370
#### Null/Undefined Handling
371
- All methods gracefully handle null or undefined children
372
- Returns appropriate empty results rather than throwing errors
373
- Consistent behavior with React.Children API
374
375
#### Type Preservation
376
- map() preserves and transforms types appropriately
377
- forEach() maintains original type information
378
- toArray() flattens while preserving element integrity
379
380
#### Context Binding
381
- map() and forEach() support optional context parameter
382
- Context is properly bound using Function.prototype.bind
383
- Enables method binding for class components
384
385
#### Array Flattening
386
- toArray() performs deep flattening of nested arrays
387
- Removes null and undefined values automatically
388
- Handles React fragments and iterables
389
390
### Common Use Cases
391
392
- **Component Enhancement**: Adding props or wrapping children
393
- **Conditional Rendering**: Showing/hiding based on child count
394
- **List Processing**: Converting children to lists or grids
395
- **Validation**: Ensuring correct number of children
396
- **Analytics**: Inspecting component composition
397
- **Higher-Order Components**: Manipulating child components