React get Children recursively

React get Children recursively

by jonahe

HTML

<div id="app"></div>

CSS

fieldset {
	margin: 0px 0px 10px 0px;
	border: 1px solid teal;
	padding: 20px;
}

div.form-element {
  border: 1px solid teal;
  padding: 20px;
}

React

const getChildrenRecursively = (soFar, parent) => {
	if(typeof parent === "string") return soFar.concat(parent);
  
	const children = Array.isArray(parent.props.children) ? 
  	parent.props.children : 
    React.Children.toArray(parent.props.children);
  
  const childCount  = children.length;
  
	if(childCount <= 0) {
  	return soFar.concat(parent);
  } else {
  	return soFar.concat([parent], children.flatMap(child => getChildrenRecursively([], child)));
  }
}

const MyInput = ({label} ) => <input placeholder={label} ></input>;


const MyComp = ({children}) => {
	const childArr = React.Children.toArray(children);
  // get all children in hierarcy
  const flattenedChildren = childArr.reduce(getChildrenRecursively, []);
  
  const numberOfInputs = flattenedChildren
  	.filter(child => child.type && child.type.name === "MyInput").length;
  
  const Wrapper = numberOfInputs > 1 ? 'fieldset' : 'div';

  
	return (
  	<div>
      	<Wrapper className="form-element">
          <legend>{numberOfInputs} input(s)</legend>
          <div>{children}</div>
        </Wrapper>
    </div>
  )
}


const App = () => {
	return (
      <div>
        <MyComp>
          <MyInput placeholder="Some input #1" />
          <div>
            <span>Some non-input element</span>
          </div>
        </MyComp>
        <MyComp>
          <MyInput placeholder="Some input #1" />
          <div>
            <div>
               <MyInput placeholder="Some nested input #2" />
            </div>
            <div>
              <span>Some non-input element</span>
            </div>
          </div>
        </MyComp>
      </div>
   )
}

ReactDOM.render(<App />, document.querySelector("#app"));