haotang
haotang

Reputation: 5738

Pass this.refs as property in jsx in React.js

I'm trying to pass 1 node as a property of another React component like this:

  render: function() {
    return (
      <div>
        <div ref='statusCircle'></div>
        <Popover trigger={ this.refs.statusCircle }></Popover>
      </div>);
    );
  }

But in the Popover, this.props.trigger is NULL.

Is there anything wrong with my code?

How can I pass a node-ref to another React component as property?

Upvotes: 4

Views: 6831

Answers (2)

Deryck
Deryck

Reputation: 7668

After typing this I realized it's really not an answer to the original question but instead a follow-up to your request for suggestions in your comment above. If you really don't believe it should stay, I'll delete it but it's too big for a comment, sorry.

Reference material

You must be using an old version of React, so this may not look right to you at first, but you could track that information using state in that parent component by doing

ref={ function ( element ) {

    // at the top of render() put
    //    var self = this;

    self.setState({ 
        circleWidth: element.offsetWidth, 
        circleHeight: element.offsetHeight 
    }) 
}

Assuming those values change over time, you'll want to add an event listener for that change (which can be added inside that ref setup) and have it run that setState again when you need it to re-render.

As for <Popover trigger= you'll want to do something to the effect of:

<Popover trigger={this.state.circleWidth > 999} />

...where 999 is whatever your trigger value would be. If it returns true, then you render Popover. If not, you destroy it. Both situations would be handled inside Popover but will not need to touch that div

Of course, good practice in React is to do that comparison at the top of render() and place the result into a variable like isTriggered.

Upvotes: 2

BluePill
BluePill

Reputation: 515

You've misunderstood the component lifecycle in React. See here: Link

See this fiddle. https://jsfiddle.net/uzvoruf7/
Open your console, inspect the code for the "Composite" component, and see the lifecycle hooks.

var Popover = React.createClass({
  render: function() {
    return (<div>This is a pop-over</div>);
  }
});

var Composite = React.createClass({
  componentDidMount: function() {
    console.log(this.refs.statusCircle); //ok, exists.
  },
  render: function() {
    console.log(this.refs.statusCircle); //doesn't exist, sorry.
    return (
      <div>
        <div ref='statusCircle'></div>
        <Popover trigger={this.refs.statusCircle}></Popover>
      </div>
    );
  }
});

ReactDOM.render(
  <Composite />,
  document.getElementById('container')
);

"refs" come alive once the DOM has been rendered.

Therefore, it follows that inside that return statement, the dom has not been rendered yet, hence the reference is null (or all references are null so to speak).

However, inside componentDidMount, you can see that your references are available just as one would expect.

This is a common error: a possible code smell that needs refactoring. Usually (not always), passing down dom-references is indicative of an imperative thought process and is not the React way. I would suggest an improvement but I'm not aware of your use-case.

Upvotes: 7

Related Questions