Skip to content

Instantly share code, notes, and snippets.

@dandelany
Last active March 27, 2024 10:06
Show Gist options
  • Star 35 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save dandelany/1ff06f4fa1f8d6f89c5e to your computer and use it in GitHub Desktop.
Save dandelany/1ff06f4fa1f8d6f89c5e to your computer and use it in GitHub Desktop.
Recursively cloning React children
var RecursiveChildComponent = React.createClass({
render() {
return <div>
{this.recursiveCloneChildren(this.props.children)}
</div>
},
recursiveCloneChildren(children) {
return React.Children.map(children, child => {
if(!_.isObject(child)) return child;
var childProps = {someNew: "propToAdd"};
childProps.children = this.recursiveCloneChildren(child.props.children);
return React.cloneElement(child, childProps);
})
}
})
@reggi
Copy link

reggi commented Sep 22, 2015

Might want to switch _.isObject to React.isValidElement.

@u0078867
Copy link

Nice piece of code! In my case, I slightly adapted it to render React components deeply nested inside DOM tags:

recursiveCloneChildren(children) {
        return React.Children.map(children, child => {
            var childProps = {};
            if (React.isValidElement(child)) {
                childProps = {someNew: "propToAdd"};
            }
            childProps.children = this.recursiveCloneChildren(child.props.children);
            return React.cloneElement(child, childProps);
        })
}

@warmhug
Copy link

warmhug commented Mar 24, 2016

@u0078867 Maybe need to check child.props additionally..

recursiveCloneChildren(children) {
        return React.Children.map(children, child => {
            var childProps = {};
            if (React.isValidElement(child)) {
                childProps = {someNew: "propToAdd"};
            }
            if (child.props) {
                // String has no Prop
                childProps.children = this.recursiveCloneChildren(child.props.children);
                return React.cloneElement(child, childProps);
            }
            return child;
        })
}

Copy link

ghost commented May 14, 2016

I want to access the children of a ReactComponent, but React wont allow this for some reason... I have this:

`



I want to access this


`

But when debugging the recursive clone function i get:

child.type: function BoughtForm()

child.props.children: undefined

child.props: Object
key: (...)
get key: function ()
ref: (...)
get ref: function ()
proto: Object

The < h1 > element doesn't show up as children. Maybe I am missing something and this is expected behaviour?

Copy link

ghost commented May 14, 2016

Never mind... Works like a charm! It was a very specific context related issue in my codebase.

However I would still like the recursive clone to include the JSX-code inside my child component as well. Is this even possible? Aka I would like to access the JSX inside a self closing element like < BoughtForm />

@jedwards1211
Copy link

Recursive cloning is the shit. I used it to stop wasting time on form boilerplate (shameless plug: https://github.com/jedwards1211/react-bind-data)

@joeshub
Copy link

joeshub commented Sep 3, 2016

Neat, but this is pretty scary for performance since you have no idea how deep the rabbit hole goes

@YourFriendChooly
Copy link

YourFriendChooly commented Mar 29, 2017

Thanks so much. I've been plugging away at this for hours, I was able to get the recursion based on the component type, but every time it traversed the next round of children it would skip rendering the original element (ie. a div tag wouldn't get rendered but its children would).. Thats because I failed to realize that I needed to clone the 'parent-child' and set it's children recursively. Kudos!

@OndeVai
Copy link

OndeVai commented Oct 20, 2017

Great stuff. Thanks!

@adamgravita
Copy link

Fantastic, was working on an issue like this for a while!

@nucab
Copy link

nucab commented Jun 27, 2018

recursiveCloneChildren(children) {
  return React.Children.map(children, (child) => {
    if (!React.isValidElement(child)) return child;
    const props = { ...{ className: '' }, ...child.props };
    let childProps = {};
    if (React.isValidElement(child) && !props.className.includes('exclude-node')) {
      childProps = {
        show: this.state.show,
        toggle: this.toggle,
      };
    }
    childProps.children = this.recursiveCloneChildren(child.props.children);
    return React.cloneElement(child, childProps);
  });
}

if you have SVG icon beneath your elements. this could be helpful.

@kurtisdunn
Copy link

This helped me to no end. Legends the lot of you!

@pavel-lens
Copy link

pavel-lens commented Nov 22, 2019

Recursive cloning React children in Typescript

Use case: A form has a global Enable/Disable switch which should make all the elements in the form disabled.

function recursiveCloneChildren(children: React.ReactElement[], newProps: any) {
  return React.Children.map(children, (child: React.ReactElement) => {
    if (!React.isValidElement(child)) {
      return child
    }
    
    // Eg. String has no props
    if (child.props) {
      // @ts-ignore
      childProps.children = recursiveCloneChildren(child.props.children, newProps);
      return React.cloneElement(child, newProps);
    }
    return child;
  });
}

In usage you need to change type.

render() {
  ...
  { recursiveCloneChildren(children as React.ReactElement[], { disabled: true }) }
   ...
}

@leonidkuznetsov18
Copy link

Recursive cloning React children in Typescript

Use case: A form has a global Enable/Disable switch which should make all the elements in the form disabled.

function recursiveCloneChildren(children: React.ReactElement[], newProps: any) {
  return React.Children.map(children, (child: React.ReactElement) => {
    if (!React.isValidElement(child)) {
      return child
    }
    
    // Eg. String has no props
    if (child.props) {
      // @ts-ignore
      childProps.children = recursiveCloneChildren(child.props.children, newProps);
      return React.cloneElement(child, newProps);
    }
    return child;
  });
}

In usage you need to change type.

render() {
  ...
  { recursiveCloneChildren(children as React.ReactElement[], { disabled: true }) }
   ...
}

childProps????? maybe newProps !!!

@matthew-dean
Copy link

What if a child component has no children, but returns a tree, and you want to recursively clone / modify the returned tree?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment