Is there any way to grab all of the bar
properties in <Wrapper/>
below 'statically', e.g. without rendering?
import React from 'react';
import ReactDOM from 'react-dom';
class Foo extends React.Component {
render() {
return(
<div>
<span bar="1" /> // want to collect this 'bar'
<span bar="2" /> // want to collect this 'bar'
</div>;
);
}
}
class FooTuple extends React.Component {
render() {
return(
<div>
<Foo />
<Foo />
</div>;
);
}
}
class Wrapper extends React.Component {
render() {
React.Children.forEach(this.props.children, child => {
console.log(child.props); // can only see <FooTuple/> not <Foo/>
});
return(
<div>
{this.props.children}
</div>;
);
}
}
ReactDOM.render(
<Wrapper>
<FooTuple />
</Wrapper>,
document.getElementById('app'));
Here's a webpackbin with a naive attempt that tries to iterate over child.children
which obviously doesn't work, but it's here if it's helpful:
Is there any way to grab all of the bar
properties in <Wrapper/>
below 'statically', e.g. without rendering?
import React from 'react';
import ReactDOM from 'react-dom';
class Foo extends React.Component {
render() {
return(
<div>
<span bar="1" /> // want to collect this 'bar'
<span bar="2" /> // want to collect this 'bar'
</div>;
);
}
}
class FooTuple extends React.Component {
render() {
return(
<div>
<Foo />
<Foo />
</div>;
);
}
}
class Wrapper extends React.Component {
render() {
React.Children.forEach(this.props.children, child => {
console.log(child.props); // can only see <FooTuple/> not <Foo/>
});
return(
<div>
{this.props.children}
</div>;
);
}
}
ReactDOM.render(
<Wrapper>
<FooTuple />
</Wrapper>,
document.getElementById('app'));
Here's a webpackbin with a naive attempt that tries to iterate over child.children
which obviously doesn't work, but it's here if it's helpful:
http://www.webpackbin.com/EySeQ-ihg
1 Answer
Reset to default 19TL;DR; Nope that's not possible.
--
I've once encountered the same problem trying to traverse a tree of deeply nested children. Here are my scoop outs:
Required knowledge
children
are what's placed inside thejsx
open and close tags, or injected directly in the children prop. other than thatchildren
prop would beundefined
.<div className="wrapper"> // Children <img src="url" /> </div> /* OR */ <div classname="wrapper" children={<img src="url" />}>
children
are an opaque tree-like data structure that represents the react elements' tree, it's likely the output ofReact.createElement
that thejsx
implements when transpiling.{ $$typeof: Symbol(react.element), type: 'div', key: null, ref: null, props: { className: "wrapper", children: { $$typeof: Symbol(react.element), type: 'img', key: null, ref: null, props: { src: 'url' }, } } }
Creating
React
elements doesn't mean that they are instantiated, think of them like a descriptor thatReact
uses to render those elements. in other words, instances are taken care off byReact
itself behind the scenes.
Traversing children
Let's take your example and try to traverse the whole tree.
<Wrapper>
<FooTuple />
</Wrapper>
The opaque children object of these elements would be something like this:
{
$$typeof: Symbol(react.element),
type: Wrapper,
key: null,
ref: null,
props: {
children: {
$$typeof: Symbol(react.element),
type: FooTuple,
key: null,
ref: null,
props: {},
}
}
}
As you can see FooTuple
props are empty for the reason you should know by now. The only way to reach it's child elements is to instantiate the element using it's type
to be able to call it's render method to grab it's underlying child elements, something like this:
class Wrapper extends React.Component {
render() {
React.Children.forEach(this.props.children, child => {
const nestedChildren = new child.type(child.props).render();
console.log(nestedChildren); // `FooTuple` children
});
return(
<div>
{this.props.children}
</div>;
);
}
}
This is obviously not something to consider at all.
Conclusion
There is no clean way to augment deeply nested children or grab something from them (like your case). Refactor your code to do that in a different manner. Maybe provide a setter function in the context
to set the data you need from any deep child.
<FooTuple>
. fromFooTuple.render()
, you could see<Foo/>
, and fromFoo.render
, your<span>
s. – dandavis Commented Mar 11, 2016 at 3:14console.log()
right now, but you're rendering it into the DOM, so the<span>s
will be in the DOM. – JMM Commented Mar 11, 2016 at 14:39name
properties (and one or two other properties) for arbitrarily deeply nested component children of the Form. I need to be able to grab them at first run/instantiation time for things like validation etc. I was thinking it should be possible to traverse the children of the form and decorate them, maybe using React.cloneElement, but I wasn't able to traverse deeper than the first-level children. – Muers Commented Mar 14, 2016 at 15:05ReactClass
es orReactElement
s or callback functions as props, and if you really want to you could use context. – JMM Commented Mar 14, 2016 at 18:20