Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

props.children is UNMOUNTED following update #1602

Closed
yang opened this issue May 25, 2014 · 5 comments
Closed

props.children is UNMOUNTED following update #1602

yang opened this issue May 25, 2014 · 5 comments

Comments

@yang
Copy link

yang commented May 25, 2014

I'm confused by the following behavior. In this example, I have a Wrapper that takes a children prop. When it first renders, clicking mounted? gives us MOUNTED which seems right. But after clicking update to re-render everything, clicking mounted? gives us UNMOUNTED.

For some real-use-case context, this gave me errors when accessing this.props.children.getDOMNode() to pass to a third-party library for displaying a pop-up menu around the given node. The given child was not responsible for knowing about the popup logic; instead, it's the sole purpose of Wrapper to show a contextual menu at the location of the given component.

Pasting this into a Live JSX Editor on http://facebook.github.io/react/ should work:

/** @jsx React.DOM */
var Wrapper = React.createClass({
  mounted: function() { alert(this.props.children._lifeCycleState); },
  showPopup: function() { alert(this.props.children.getDOMNode()); },
  render: function() {
    return <div>
      {this.props.children}
      <button onClick={this.mounted}>mounted?</button>
      <button onClick={this.props.onUpdate}>update</button>
      <button onClick={this.showPopup}>show popup</button>
    </div>;
  }
});
var App = React.createClass({
  handleUpdate: function() { this.forceUpdate(); },
  render: function() {
    return (
      <Wrapper onUpdate={this.handleUpdate}>
        <div>hello world</div>
      </Wrapper>
    );
  }
});
React.renderComponent(<App />, mountNode);

I believe I'm seeing the same behavior in general when accessing props.children of any ref.

@sophiebits
Copy link
Collaborator

As the underscore in front of its name suggests, _lifeCycleState is private to React and you should not use it in your own code.

There's no current way to get a reference to the mounted children instance, but you can use a ref if you wrap them in another div:

var Wrapper = React.createClass({
  showPopup: function() { alert(this.refs.childWrapper.getDOMNode()); },
  render: function() {
    return <div>
      <div ref="childWrapper">
        {this.props.children}
      </div>
      <button onClick={this.props.onUpdate}>update</button>
      <button onClick={this.showPopup}>show popup</button>
    </div>;
  }
});

Hope that helps.

@yang
Copy link
Author

yang commented May 26, 2014

I'm not actually using _lifeCycleState—it's just in this example to pinpoint the problem.

Inserting an intermediate div unfortunately violates assumptions (e.g. CSS layout, doesn't work for SVGs, etc.).

@sophiebits
Copy link
Collaborator

Sorry, there's no way right now to get a ref to children that are passed in. After #1373 it may be possible to do so using cloneWithProps.

@yang
Copy link
Author

yang commented May 26, 2014

Thanks, I had been following that.

Actually, following up on your mentioning cloneWithProps and some further experimentation—can't you already get it via the following? At least, seems to work for me (example in CoffeeScript):

Wrapper = React.createClass
  render: ->
    R.div {},
      cloneWithProps @props.children, ref: 'handle'
      R.button {onClick: => console.log @refs.handle}, 'inspect'

Perhaps there are pitfalls to using cloneWithProps that aren't documented?

Also, some random other experimentation suggests that at least one other way to actually get the DOM node using a pass-through component without the extra div.

PassThrough = React.createClass
  render: -> @props.children

Wrapper = React.createClass
  render: ->
    R.div {},
      PassThrough {ref: 'handle'}, @props.children
      R.button {onClick: => console.log @refs.handle.getDOMNode()}, 'inspect DOM'

@sophiebits
Copy link
Collaborator

Ah yes, you're right on both counts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants