facebook / react

The library for web and native user interfaces.
https://react.dev
MIT License
229.88k stars 47.06k forks source link

Error message for using refs outside of render() is difficult to understand #383

Closed petehunt closed 10 years ago

petehunt commented 11 years ago

Something about "only a ReactOwner can have refs" -- it's not intuitive.

jgorham commented 10 years ago

Yeah I just saw this and had a wtf

petehunt commented 10 years ago

Would love to add you to the contributors list! :)

bitshadow commented 10 years ago

@petehunt What should be the message then? I can submit a patch.

petehunt commented 10 years ago

@bitshadow something along the lines of: "Only a ReactOwner can have refs. This usually means that you're trying to add a ref to a component that doesn't have an owner (that is, was not created inside of another component's render() method. Try rendering this component inside of a new top-level component which will hold the ref."

plievone commented 10 years ago

Fixed in 72fd246

ninjasort commented 9 years ago

Hello, I'm running into this issue and am unclear on what this actually means. I have a component in ES6 which works fine in ES5, but throws this error when bundling a simple example. https://github.com/cameronjroe/test-react-star-rating Any idea what I'm doing wrong? https://github.com/cameronjroe/react-star-rating/blob/es6/src/StarRating.jsx#L213

bitshadow commented 9 years ago

@cameronjroe Owner-ownee relationship is specific to react components. React uses <span> from DOM and is not created with React.CreateClass. In react terminology its a parent and not owner.

This will help you get clear idea about this. Hope this helps.

ninjasort commented 9 years ago

So does that mean you can't use refs on DOM nodes within a component?

bitshadow commented 9 years ago

No that doesn't mean that (input heavily uses it). You will have to move your span (which doesn't have owner) element to some other component and render it in component's render method and use that component at :213 with ref.

desmondhume commented 9 years ago

Same issue here. This is my code:

var DropdownList = require('react-widgets/lib/DropdownList');

var Dropdown = React.createClass({
  render: function() {
    return (
      <div>
        <span>Dropdown</span>
        <DropdownList data={this.props.colors} />
      </div>
    )
  }
});

module.exports = Dropdown;

It seems to build part of the component, but then fails with:

Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. This usually means that you're trying to add a ref to a component that doesn't have an owner (that is, was not created inside of another component's 'render' method). Try rendering this component inside of a new top-level component which will hold the ref.

Suggestions/ideas? Am I missing something?

syranide commented 9 years ago

@desmondhume That makes no sense, there aren't no refs in your example code. The error is originating somewhere else in your case. Invoking <Comp ref="foo" /> anywhere but as a result of render() will cause that error to be thrown.

desmondhume commented 9 years ago

@syranide you're right, my problem seems to be related to this issue #3320. If I copy & paste the module instead of installing it via npm, it works just right. I don't know what's going on actually.

syranide commented 9 years ago

@desmondhume NPM has probably installed two separate React's for you, and the module requires it's own.

ninjasort commented 9 years ago

@bitshadow I'm not following you. If I can use refs on DOM nodes, how is using a ref on a <span> any different from this example. This span is in a render method, on an Owner (StarRating). No?

bitshadow commented 9 years ago

Well there are wrappers written for the some specific elements which requires user's interactions or some additional functionality (test). I still didn't see how other DOM elements are handling the refs when there is no owner. I will have to figure it out.

ninjasort commented 9 years ago

Yeah, I don't see span in the wrappers.. any ideas on how it's handling refs?

rulatir commented 8 years ago

The problem is not the error message, but the limitation the message is telling you about. This limitation should be removed. <rant>I'm no longer completely new to react, but I still keep running into more and more stupid barriers that have no reason whatsoever to be there, other than someone's idea of "separation" of something, resulting in 90% percent of programmer time being spent on drilling through arbitrarily placed concrete walls just to get this piece of data or that API from this place in code to that other place. Simple heuristic: if I create (e.g. instantiate) something, I will probably be using it. DON'T make it hard.</rant>

gaearon commented 8 years ago

I'm no longer completely new to react, but I still keep running into more and more stupid barriers that have no reason whatsoever to be there, other than someone's idea of "separation" of something

I’m not sure the problem you have is due to “someone’s idea of separation of something”. Perhaps it’s a valid technical limitation that exists for a reason. Or maybe this is something we could fix!

In such cases, rather than write a comment in a tangentially related thread, it would be more productive to create a new issue describing what you were trying to achieve and how React gets in the way of that.

Maybe we can help you by finding a simpler way to achieve the same, or maybe your issue will help us find a better API! Unfortunately this thread is not really a good place for this discussion because it’s not clear what you were trying to do, and your feature request does not correspond to the issue being discussed.

Would you please create an issue describing your use case and the problem with some code snippets? Please believe me that nobody here wants to put barriers in front of you, or to force you to separate anything out of spite :smile: . Thanks!

syranide commented 8 years ago

@rulatir @gaearon refs={c => this._node = c} is free of any such restrictions and the reason you can't do what you want is because old-style refs has to be owned by the creator (by necessity), but that obviously only works if React can figure out which instance is the creator, which it only can in some specific instances, hence the new refs api.