How to check how many React children have a certain prop?

- 1 answer

Ad

I have two types of components. Let's call them Outer and Inner. Imagine something like this:

<Outer>
    <h4>{this.prop.title} ({this.state.withX}/{this.state.total})</h4>
    <Inner isX/>
    <Inner isX/>
    <Inner/>
    <Inner/>
</Outer>

I have this function:

getInitialState: function() {
    return {
        total: React.Children.count(this.props.children),
        withX: /// ??? ///
    };
}

How do I get that value? I was trying to get something like this:

withX: function() {
    var counter = React.Children.forEach(this.props.children, function(child) {
         // if...
         return //something
    });
return counter;
}

But... I feel it'll get me nowhere.

Ad

Answer

Ad

When you iterate over the children, you can inspect their props. For instance, using the forEach method you have above, you could do something like this:

withX: function() {
  var counter = 0;
  React.Children.forEach(this.props.children, function(child) {
    if (child.props.isX) counter++;
  });
  return counter;
}

React also provides a toArray helper that lets you do the same thing using the nice array methods JS provides:

return React.Children.toArray(this.props.children).filter(function(child) {
  return child.props.isX;
}).length;

If you're using ES6, can do this quite succinctly with an arrow function:

return React.Children.toArray(this.props.children).filter(c => c.props.isX).length;

The only catch is that, if Outer is doing the counting, then Outer also needs to render the h4. Here's a full example:

const App = React.createClass({
  render() {
    return (
      <Outer title="Things">
        <Inner isX/>
        <Inner isX/>
        <Inner/>
        <Inner/>
      </Outer>
    );
  }
});

const Outer = React.createClass({
  getInitialState() {
    return {
      total: React.Children.count(this.props.children),
      withX: this.countChildrenWithX(this.props.children)
    };
  },

  countChildrenWithX(children) {
    const { toArray } = React.Children;
    return toArray(children).filter(c => c.props.isX).length;
  },

  render() {
    return (
      <div>
        <h4>{this.props.title} ({this.state.withX}/{this.state.total})</h4>
        <hr />
        {this.props.children}
      </div>
    );
  }
});

const Inner = React.createClass({
  render() {
    return <div>Inner - withX = {String(!!this.props.isX)}</div>;
  }
});

And here's a working JS Bin to demonstrate: https://jsbin.com/xameyun/edit?js,output

Ad
source: stackoverflow.com
Ad