React: Get `props.children` DOM handle: `React.findDOMNode(child)`

Created on 29 Jun 2015  路  10Comments  路  Source: facebook/react

When trying to use React.findDOMNode on a props.children item(ReactElement), an error is thrown.

Uncaught Error: Invariant Violation: Element appears to be neither ReactComponent nor DOMNode

Here is a small demo that shows off the problem.

React.Children.forEach(this.props.children, (child) => {
    console.log(React.findDOMNode(child));        
});

The parent component is mounted console.log('isMounted', this.isMounted()); -> isMounted true.


Related to #1602 and #1373.

Additionally the behavior of didMount and didUpdate handlers are currently undefined in regards to when they fire in relation to their children and therefore refs. For example componentDidUpdate is not guaranteed to fire after the children has fully mounted.

_From sebmarkbage, Source_

Most helpful comment

@spicyj Thank you for the info and correction.

Here is a working demo with React.cloneElement. _React.addons.cloneWithProps is deprecated_:

// `render`
React.Children.map(this.props.children, (child) => {
    return React.cloneElement(child, {
        ref: `item-${child.props.key}`
    });
});

// ...

// `componentDidMount` or `componentDidUpdate`
React.Children.forEach(this.props.children, (child) => {        
    console.log(React.findDOMNode(this.refs[`item-${child.props.key}`]));        
});

All 10 comments

This behavior is correct. If you want to find one of your children's DOM nodes, you have to add a ref first (using React.cloneElement) and then use that ref. (An element is little more than the type and props of what you want to render; it doesn't have identity and doesn't correspond to a DOM node directly.)

(The next commend in the thread you linked contradicts that. We do guarantee that children have their componentDidMount/DidUpdate called before the parent gets it.)

@spicyj Thank you for the info and correction.

Here is a working demo with React.cloneElement. _React.addons.cloneWithProps is deprecated_:

// `render`
React.Children.map(this.props.children, (child) => {
    return React.cloneElement(child, {
        ref: `item-${child.props.key}`
    });
});

// ...

// `componentDidMount` or `componentDidUpdate`
React.Children.forEach(this.props.children, (child) => {        
    console.log(React.findDOMNode(this.refs[`item-${child.props.key}`]));        
});

@spicyj how would you handle a situation where some child component should find a dom node down stream?

For instance:

render() {
  return <SomethingThatWillFindStuff>
    <div ref="parentDiv">
      <div ref="iShouldBeFound">find me</div>
    </div>
  </SomethingThatWillFindStuff>;
}

SomethingThatWillFindStuff cannot simply clone <div ref="iShouldBeFine">find me</div> as <div ref="parentDiv">'s props are obviously immutable.

I'm wondering the same thing as @mikkoh, any solution?

@spicyj Also looking for an answer to the question @mikkoh asked.

@spicyj It may not be possible or feasible to add refs to children nodes, in which case how does one query a DOM node downstream from a .props.children reference?

@miguel-guedes @VinSpee @miguel-guedes: Look at the solution @MadLittleMods provided, his solution is correct.

SomethingThatWillFindStuff cannot simply clone <div ref="iShouldBeFine">find me</div> as <div ref="parentDiv">'s props are obviously immutable.

Immutable props does not prevent cloning.

It may not be possible or feasible to add refs to children nodes, in which case how does one query a DOM node downstream from a .props.children reference?

If you use callback refs, it's always feasible, because you can have the new callback ref also call the previous callback ref, making it completely transparent. Or you can have whomever does have the ref pass down a reference to the actual dom node. Or you can call ReactDOM.findDOMNode(this) and walk the DOM. The recommended solution is to attach a ref.

Having said all that... Usage questions are better answered on sites like StackOverflow, as we try to use github issues for tracking bugs in the React core. We generally do not answer usage questions on github.

@MadLittleMods if some child has his own ref attribute, and some others child without this attribute,

return React.cloneElement(child, {
    ref: `item-${child.props.key}`
});

item-${child.props.key} can override child own ref ? or how to get child own ref ?

Unfortunately it's not possible to add a ref to a functional component, so how can we find the DOM node of a children that is a functional component?

Was this page helpful?
0 / 5 - 0 ratings