Movatterモバイル変換


[0]ホーム

URL:


Is this page useful?

Pitfall

UsingChildren is uncommon and can lead to fragile code.See common alternatives.

Children lets you manipulate and transform the JSX you received as thechildren prop.

constmappedChildren =Children.map(children,child=>
<divclassName="Row">
{child}
</div>
);

Reference

Children.count(children)

CallChildren.count(children) to count the number of children in thechildren data structure.

import{Children}from'react';

functionRowList({children}){
return(
<>
<h1>Total rows:{Children.count(children)}</h1>
...
</>
);
}

See more examples below.

Parameters

  • children: The value of thechildren prop received by your component.

Returns

The number of nodes inside thesechildren.

Caveats

  • Empty nodes (null,undefined, and Booleans), strings, numbers, andReact elements count as individual nodes. Arrays don’t count as individual nodes, but their children do.The traversal does not go deeper than React elements: they don’t get rendered, and their children aren’t traversed.Fragments don’t get traversed.

Children.forEach(children, fn, thisArg?)

CallChildren.forEach(children, fn, thisArg?) to run some code for each child in thechildren data structure.

import{Children}from'react';

functionSeparatorList({children}){
constresult =[];
Children.forEach(children,(child,index)=>{
result.push(child);
result.push(<hrkey={index}/>);
});
// ...

See more examples below.

Parameters

  • children: The value of thechildren prop received by your component.
  • fn: The function you want to run for each child, similar to thearrayforEach method callback. It will be called with the child as the first argument and its index as the second argument. The index starts at0 and increments on each call.
  • optionalthisArg: Thethis value with which thefn function should be called. If omitted, it’sundefined.

Returns

Children.forEach returnsundefined.

Caveats

  • Empty nodes (null,undefined, and Booleans), strings, numbers, andReact elements count as individual nodes. Arrays don’t count as individual nodes, but their children do.The traversal does not go deeper than React elements: they don’t get rendered, and their children aren’t traversed.Fragments don’t get traversed.

Children.map(children, fn, thisArg?)

CallChildren.map(children, fn, thisArg?) to map or transform each child in thechildren data structure.

import{Children}from'react';

functionRowList({children}){
return(
<divclassName="RowList">
{Children.map(children,child=>
<divclassName="Row">
{child}
</div>
)}
</div>
);
}

See more examples below.

Parameters

  • children: The value of thechildren prop received by your component.
  • fn: The mapping function, similar to thearraymap method callback. It will be called with the child as the first argument and its index as the second argument. The index starts at0 and increments on each call. You need to return a React node from this function. This may be an empty node (null,undefined, or a Boolean), a string, a number, a React element, or an array of other React nodes.
  • optionalthisArg: Thethis value with which thefn function should be called. If omitted, it’sundefined.

Returns

Ifchildren isnull orundefined, returns the same value.

Otherwise, returns a flat array consisting of the nodes you’ve returned from thefn function. The returned array will contain all nodes you returned except fornull andundefined.

Caveats

  • Empty nodes (null,undefined, and Booleans), strings, numbers, andReact elements count as individual nodes. Arrays don’t count as individual nodes, but their children do.The traversal does not go deeper than React elements: they don’t get rendered, and their children aren’t traversed.Fragments don’t get traversed.

  • If you return an element or an array of elements with keys fromfn,the returned elements’ keys will be automatically combined with the key of the corresponding original item fromchildren. When you return multiple elements fromfn in an array, their keys only need to be unique locally amongst each other.


Children.only(children)

CallChildren.only(children) to assert thatchildren represent a single React element.

functionBox({children}){
constelement =Children.only(children);
// ...

Parameters

  • children: The value of thechildren prop received by your component.

Returns

Ifchildrenis a valid element, returns that element.

Otherwise, throws an error.

Caveats

  • This method alwaysthrows if you pass an array (such as the return value ofChildren.map) aschildren. In other words, it enforces thatchildren is a single React element, not that it’s an array with a single element.

Children.toArray(children)

CallChildren.toArray(children) to create an array out of thechildren data structure.

import{Children}from'react';

exportdefaultfunctionReversedList({children}){
constresult =Children.toArray(children);
result.reverse();
// ...

Parameters

  • children: The value of thechildren prop received by your component.

Returns

Returns a flat array of elements inchildren.

Caveats

  • Empty nodes (null,undefined, and Booleans) will be omitted in the returned array.The returned elements’ keys will be calculated from the original elements’ keys and their level of nesting and position. This ensures that flattening the array does not introduce changes in behavior.

Usage

Transforming children

To transform the children JSX that your componentreceives as thechildren prop, callChildren.map:

import{Children}from'react';

functionRowList({children}){
return(
<divclassName="RowList">
{Children.map(children,child=>
<divclassName="Row">
{child}
</div>
)}
</div>
);
}

In the example above, theRowList wraps every child it receives into a<div className="Row"> container. For example, let’s say the parent component passes three<p> tags as thechildren prop toRowList:

<RowList>
<p>This is the first item.</p>
<p>This is the second item.</p>
<p>This is the third item.</p>
</RowList>

Then, with theRowList implementation above, the final rendered result will look like this:

<divclassName="RowList">
<divclassName="Row">
<p>This is the first item.</p>
</div>
<divclassName="Row">
<p>This is the second item.</p>
</div>
<divclassName="Row">
<p>This is the third item.</p>
</div>
</div>

Children.map is similar toto transforming arrays withmap(). The difference is that thechildren data structure is consideredopaque. This means that even if it’s sometimes an array, you should not assume it’s an array or any other particular data type. This is why you should useChildren.map if you need to transform it.

Fork
import{Children}from'react';exportdefaultfunctionRowList({children}){return(<divclassName="RowList">{Children.map(children,child=><divclassName="Row">{child}</div>)}</div>);}
Deep Dive

Why is the children prop not always an array?

In React, thechildren prop is considered anopaque data structure. This means that you shouldn’t rely on how it is structured. To transform, filter, or count children, you should use theChildren methods.

In practice, thechildren data structure is often represented as an array internally. However, if there is only a single child, then React won’t create an extra array since this would lead to unnecessary memory overhead. As long as you use theChildren methods instead of directly introspecting thechildren prop, your code will not break even if React changes how the data structure is actually implemented.

Even whenchildren is an array,Children.map has useful special behavior. For example,Children.map combines thekeys on the returned elements with the keys on thechildren you’ve passed to it. This ensures the original JSX children don’t “lose” keys even if they get wrapped like in the example above.

Pitfall

Thechildren data structuredoes not include rendered output of the components you pass as JSX. In the example below, thechildren received by theRowList only contains two items rather than three:

  1. <p>This is the first item.</p>
  2. <MoreRows />

This is why only two row wrappers are generated in this example:

Fork
importRowListfrom'./RowList.js';exportdefaultfunctionApp(){return(<RowList><p>This is the first item.</p><MoreRows/></RowList>);}functionMoreRows(){return(<><p>This is the second item.</p><p>This is the third item.</p></>);}

There is no way to get the rendered output of an inner component like<MoreRows /> when manipulatingchildren. This is whyit’s usually better to use one of the alternative solutions.


Running some code for each child

CallChildren.forEach to iterate over each child in thechildren data structure. It does not return any value and is similar to thearrayforEach method. You can use it to run custom logic like constructing your own array.

Fork
import{Children}from'react';exportdefaultfunctionSeparatorList({children}){constresult =[];Children.forEach(children,(child,index)=>{result.push(child);result.push(<hrkey={index}/>);});result.pop();// Remove the last separatorreturnresult;}

Pitfall

As mentioned earlier, there is no way to get the rendered output of an inner component when manipulatingchildren. This is whyit’s usually better to use one of the alternative solutions.


Counting children

CallChildren.count(children) to calculate the number of children.

Fork
import{Children}from'react';exportdefaultfunctionRowList({children}){return(<divclassName="RowList"><h1className="RowListHeader">        Total rows:{Children.count(children)}</h1>{Children.map(children,child=><divclassName="Row">{child}</div>)}</div>);}

Pitfall

As mentioned earlier, there is no way to get the rendered output of an inner component when manipulatingchildren. This is whyit’s usually better to use one of the alternative solutions.


Converting children to an array

CallChildren.toArray(children) to turn thechildren data structure into a regular JavaScript array. This lets you manipulate the array with built-in array methods likefilter,sort, orreverse.

Fork
import{Children}from'react';exportdefaultfunctionReversedList({children}){constresult =Children.toArray(children);result.reverse();returnresult;}

Pitfall

As mentioned earlier, there is no way to get the rendered output of an inner component when manipulatingchildren. This is whyit’s usually better to use one of the alternative solutions.


Alternatives

Note

This section describes alternatives to theChildren API (with capitalC) that’s imported like this:

import{Children}from'react';

Don’t confuse it withusing thechildren prop (lowercasec), which is good and encouraged.

Exposing multiple components

Manipulating children with theChildren methods often leads to fragile code. When you pass children to a component in JSX, you don’t usually expect the component to manipulate or transform the individual children.

When you can, try to avoid using theChildren methods. For example, if you want every child ofRowList to be wrapped in<div className="Row">, export aRow component, and manually wrap every row into it like this:

Fork
import{RowList,Row}from'./RowList.js';exportdefaultfunctionApp(){return(<RowList><Row><p>This is the first item.</p></Row><Row><p>This is the second item.</p></Row><Row><p>This is the third item.</p></Row></RowList>);}

Unlike usingChildren.map, this approach does not wrap every child automatically.However, this approach has a significant benefit compared to theearlier example withChildren.map because it works even if you keep extracting more components. For example, it still works if you extract your ownMoreRows component:

Fork
import{RowList,Row}from'./RowList.js';exportdefaultfunctionApp(){return(<RowList><Row><p>This is the first item.</p></Row><MoreRows/></RowList>);}functionMoreRows(){return(<><Row><p>This is the second item.</p></Row><Row><p>This is the third item.</p></Row></>);}

This wouldn’t work withChildren.map because it would “see”<MoreRows /> as a single child (and a single row).


Accepting an array of objects as a prop

You can also explicitly pass an array as a prop. For example, thisRowList accepts arows array as a prop:

Fork
import{RowList,Row}from'./RowList.js';exportdefaultfunctionApp(){return(<RowListrows={[{id:'first',content:<p>This is the first item.</p>},{id:'second',content:<p>This is the second item.</p>},{id:'third',content:<p>This is the third item.</p>}]}/>);}

Sincerows is a regular JavaScript array, theRowList component can use built-in array methods likemap on it.

This pattern is especially useful when you want to be able to pass more information as structured data together with children. In the below example, theTabSwitcher component receives an array of objects as thetabs prop:

Fork
importTabSwitcherfrom'./TabSwitcher.js';exportdefaultfunctionApp(){return(<TabSwitchertabs={[{id:'first',header:'First',content:<p>This is the first item.</p>},{id:'second',header:'Second',content:<p>This is the second item.</p>},{id:'third',header:'Third',content:<p>This is the third item.</p>}]}/>);}

Unlike passing the children as JSX, this approach lets you associate some extra data likeheader with each item. Because you are working with thetabs directly, and it is an array, you do not need theChildren methods.


Calling a render prop to customize rendering

Instead of producing JSX for every single item, you can also pass a function that returns JSX, and call that function when necessary. In this example, theApp component passes arenderContent function to theTabSwitcher component. TheTabSwitcher component callsrenderContent only for the selected tab:

Fork
importTabSwitcherfrom'./TabSwitcher.js';exportdefaultfunctionApp(){return(<TabSwitchertabIds={['first','second','third']}getHeader={tabId=>{returntabId[0].toUpperCase() +tabId.slice(1);}}renderContent={tabId=>{return<p>This is the{tabId} item.</p>;}}/>);}

A prop likerenderContent is called arender prop because it is a prop that specifies how to render a piece of the user interface. However, there is nothing special about it: it is a regular prop which happens to be a function.

Render props are functions, so you can pass information to them. For example, thisRowList component passes theid and theindex of each row to therenderRow render prop, which usesindex to highlight even rows:

Fork
import{RowList,Row}from'./RowList.js';exportdefaultfunctionApp(){return(<RowListrowIds={['first','second','third']}renderRow={(id,index)=>{return(<RowisHighlighted={index %2 ===0}><p>This is the{id} item.</p></Row>);}}/>);}

This is another example of how parent and child components can cooperate without manipulating the children.


Troubleshooting

I pass a custom component, but theChildren methods don’t show its render result

Suppose you pass two children toRowList like this:

<RowList>
<p>First item</p>
<MoreRows/>
</RowList>

If you doChildren.count(children) insideRowList, you will get2. Even ifMoreRows renders 10 different items, or if it returnsnull,Children.count(children) will still be2. From theRowList’s perspective, it only “sees” the JSX it has received. It does not “see” the internals of theMoreRows component.

The limitation makes it hard to extract a component. This is whyalternatives are preferred to usingChildren.



[8]ページ先頭

©2009-2025 Movatter.jp