35

According to the react docs, if a component has multiple children, this.props.children should be an array.

I have the following component:

export class Two extends React.Component {

    componentDidMount() {
        console.log(Array.isArray(this.props.children)); // false
    }

    render() {

        return(
            <div>
                {this.props.children}
            </div>
        );
    }

};

Which I pass children to in another component's render() method:

<Two>
    <Img src="/photos/tomato.jpg"/>
    <Img src="/photos/tomato.jpg"/>
</Two>

Why is this.props.children not an array? More importantly, how can I get it to be one?

6
  • 2
    Also according to the docs, children is an opaque data structure. Commented Sep 19, 2015 at 20:43
  • 4
    What do you need to do with this.props.children? If you want to iterate all the children than you have tools like in React Children utilities. Commented Sep 19, 2015 at 21:54
  • Is it because Img is capitalized? Commented Sep 20, 2015 at 17:50
  • @ZackArgyle Img is a custom component that I created Commented Sep 21, 2015 at 3:40
  • @DavinTryon That ultimately worked but it feels a bit clunky for something that I imagine is quite common. This did the trick: let children = []; React.Children.forEach(this.props.children, function(child) { children.push(child); }); Commented Sep 21, 2015 at 3:41

6 Answers 6

57

Found a better solution to this after some digging in the React.Children source. It looks like a .toArray() method has been added in React 0.14, soon to be released.

Once it is out we will be able to simply do something like this:

let children = React.Children.toArray(this.props.children);

It's documented in https://reactjs.org/docs/react-api.html#reactchildren

Sign up to request clarification or add additional context in comments.

1 Comment

There's actually an entire API for working with props.children: facebook.github.io/react/docs/react-api.html#react.children. props.children itself is considered "opaque" and no assumptions should be made about its implementation - see github.com/facebook/react/issues/751.
6

I found this solution. It will render all children, one or more.

const BigMama = ({ children, styles, className }) => {
  return (
    <div
      styles={{styles}}
      className={(className ? className : '')}
    >
    {
      React.Children.map(children, (child) =>
        <React.Fragment>{child}</React.Fragment>)
    }
  </div>)
}


<BigMama
  styles={{border: 'solid groove'}}
  className='bass-player'
>
  <h1>Foo</h1>
  <h2>Bar</h2>
  <h3>Baz</h3>
  <h4>Impossibru!</h4>
<BigMama>

Comments

2

If you want to do something with the results (eg. render the array in a list), this is how you can use children. The React docs talk about how the map function works with children, as it's an opaque structure.

export const List = ({ children }) => {
  return (
    <ul>
      {React.Children.map(children, child => <li>{child}</li>)}
    </ul>
  )
}

So then you can call

<List>
  {item.name}
  {item.price}
</List>

Comments

1

There are many ways and some are mentioned above already but if you wanna keep it simple and want to achieve this without any utility then below should work

const content = [
  <Img src="/photos/tomato.jpg"/>,
  <Img src="/photos/tomato.jpg"/>
];

<Two>
  {content}
</Two>

Comments

1

You might find the spread syntax useful in this case. Have you tried it out?

<div>
    { [...this.props.children] }
</div>

Combine with map to manipulate the output.

<div>
    { [...this.props.children].map(obj => <div style="someStyling"> {obj} </div> ) }
</div>

1 Comment

I love this, but in typescript I get: Type 'ReactNode' must have a '[Symbol.iterator]()' method that returns an iterator.ts(2488) sadly.
0

Is it because is it a DOM node? Try console.log(this.props.children) you will notice that it logged a array of objects (note that each object contains information of the child element of the component). I read that node and array are not the same tho they have a same format. Visit Javascript DOMNode List for more information.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.