JedWatson / react-select

The Select Component for React.js
https://react-select.com/
MIT License
27.58k stars 4.12k forks source link

Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs #606

Closed mockdeep closed 7 years ago

mockdeep commented 8 years ago

Trying to integrate react-select into our application and we're seeing the following error. There may be something in our workflow that is causing it. We're using ReactDOM to render react components into our page.

Uncaught Error: Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's `render` method, or you have multiple copies of React loaded (details: https://fb.me/react-refs-must-have-owner).

An example:

// other code
function init() {
  model.on('change', renderRecipientDisplay);
}

function logChange(val) { console.log("Selected: " + val); }

function renderRecipientDisplay() {
  var ReactSelect = require('react-select');
  var options = [{ value: 'one', label: 'One' }, { value: 'two', label: 'Two' }];

  ReactDOM.render(
    (
      <ReactSelect name="form-field-name" value="one" options={options} onChange={logChange} />
    ),
    $el.find('.routing-recipient-display')[0]
  );
}
albertoclarit commented 8 years ago

I encounter this problem few days ago with the same message as you got from the console...

The reason was React module was loaded twice. I had an html file that contains

<script type="text/javascript" src="<@spring.url "/react/react.min.js"/>"></script>
<script type="text/javascript" src="<@spring.url "/react/react-dom.min.js"/>"></script>
<script type="text/javascript" src="<@spring.url "/react/components/compiled/subcontract.js"/>"></script>

and subcontract.js is generated by webpack. The problem was one of the modules inside subcontract has a dependency to React module and webpack has also bundled that into the compiled subcontract.js. Therefore two React module was loaded in the page...

mockdeep commented 8 years ago

Yeah, I was trying to explore the same possibility. How did you end up resolving it? Right now we have a version required in our application code, but it looks like react-select is maybe pulling in another copy for some reason.

jeromegn commented 8 years ago

I'm getting the same error, with no indication that I'm loading React more than once.

I'm trying to render <Select /> within one of my other components. Apparently that's not possible since this is using refs. I'm not entirely sure why yet.

This project has figured if they removed refs, it might be easier to nest this component inside another component: https://github.com/bebraw/reactabular/issues/41

radar commented 8 years ago

I'm also getting this error. I will attempt to reproduce this issue in a new application.

jeromegn commented 8 years ago

In the end, it really was React being loaded too many times.

I don't believe the browserify shimming applies to installed node modules. Therefore instead of using the global React, it imports another one. I don't feel like this is an issue with react-select. At least for me, it's an issue with browserify loading multiple copies of the same library (React) when requested more than once by other modules.

If I assign React to global.React and remove all requires of it in the react-select and react-input-autosize files, it works just fine.

mockdeep commented 8 years ago

Is it possible react-select is defining its own require in spite of browserify, so it doesn't have the same reference?

mockdeep commented 8 years ago

Dug in a little deeper and there are two versions of react in my node_modules directory:

node_modules/react/

and

node_modules/react-select/node_modules/react/

I modified the ReactVersion file of each of these and discovered that my application is pulling in the top one, but react-select is pulling in the bottom. What next?

mockdeep commented 8 years ago

I updated npm to 3.4.1 which flattens dependencies and I'm still seeing this issue. I've confirmed that both react-select and my application are both using the same copy of react.

albertoclarit commented 8 years ago

try switching to webpack.. i did not encounter the problem anymore after i remove the

<script type="text/javascript" src="<@spring.url "/react/react.min.js"/>"></script>
<script type="text/javascript" src="<@spring.url "/react/react-dom.min.js"/>"></script>
hpaul commented 8 years ago

I encounter same problem, but it's not caused by duplicate react dependecy.

I'm Implementing a separate form library and React say that I can't use refs outside of ReactOwner. So, I can't include a react component which use refs. But if I include react-select in main application it works.

This is how I wrap react-select:

import React, { PropTypes, Component } from 'react';
import Select from 'react-select';
import styles from './select.scss';
import withStyles from '../../decorators/withStyles';
import {connect} from 'react-redux';
import { setValue } from '../../actions/validation';

@withStyles(styles)
class Container extends Component {

  render() {
    return (
      <div>
        <Select ref="selectbox" {...this.props} />
      </div>
    );
  }
}

export default connect(state => ({
  validation: state.validation,
}))(Container);

It's a select component. screen shot 2015-12-08 at 18 29 02

nburwell commented 8 years ago

I am running into this issue too, using browserify-shim with the following external config:

module.exports = {
  "react": { exports: "global:React" },
  "react-dom": { exports: "global:ReactDOM" }
};

(As we had to load React on the page itself because other code on the page outside of the component I am trying to build relies on it). That was all working fine, until we did the following:

var React = require('react');
var Select = require('react-select');  // <--------- this ends up pulling in a second version of react rather than using the shim / global

module.exports = React.createClass({
  render: function() {
    var options = [
      { value: 'one', label: 'One' },
      { value: 'two', label: 'Two' }
    ];

    return(
      <Select options={options}></Select>
    );
  }
});

Has anyone resolved or worked around this issue while still using browserify-shim for React? It seems like browserify should be using the same configuration when resolving the requires down in a node_module package.

mockdeep commented 8 years ago

We ended up giving up on react-select for the time being.

davidmilo commented 8 years ago

Anyone figured this out? I am still having same issue.

davidmilo commented 8 years ago

I tried with a simple component (cjsx syntax)

React = require('react')
Select = require('react-select')

@Test = React.createClass
  render: ->
    <div>
      <h1>Does it work?</h1>
      <Select />
    </div>

module.exports = @Test

But I still get the same error. I tried to remove all require('react') and require('react-dom') from react-select but error persists. I think it is related to the usage of refs in your code maybe? I tried both versions 0.9.1 and 1.0.0-beta9.

I will have to give up on react-select same as @mockdeep unless someone has some suggestions?

c9s commented 8 years ago

I guess it's caused by the refs used in the methods of the mixins.

cubbuk commented 8 years ago

Just for an information, I receive this error when I add a new dependency to the project. If I delete node_modules and reinstall all the dependencies the error does not occur again.

aneeshpu commented 8 years ago

same as cubbuk. I deleted node_modules and reinstalled all dependencies. The error went away

kesha-antonov commented 8 years ago

Reinstalling node_modules unfortunately didn't work for me. Please fix this

kesha-antonov commented 8 years ago

Ok, soled it. Got separate file with React. Stop requiring packages locally and require them with npm (from node_modules) solved it.

salman-virk commented 8 years ago

@kesha-antonov I am having the same problem. I deleted node_modules and reinstalled by running npm install. But, I still see the error. What do you mean by 'Stop requiring locally'?

kesha-antonov commented 8 years ago

I had file ".../my_directory/react.js"

And in package.json

"browser": {
   "react": ".../my_directory/react.js",
   ...

I removed that line from "browser" block and also "react-dom", "formsy-react" and did npm install react react-dom formsy-react --save

And then I succeed @salman-virk

ttrinh commented 8 years ago

More solutions here in case anyone needs https://gist.github.com/jimfb/4faa6cbfb1ef476bd105

iainbeeston commented 8 years ago

For me this issue was caused by using turbolinks with react-select. I didn't have time to get to figure out exactly what turbolinks was doing to cause the issue but (based on the other comments in this thread) I suspect it was reloading react when I changed pages. Removing turbolinks stopped this from happening (although there probably is a way to successfully use react-select alongside turbolinks).

vkbr commented 8 years ago

I found a hacky solution.

In the dependent component instead of just exporting the React component I am exporting a function which returns the React component

select.jsx

module.exports = function (React) {
    var Select = React.createClass({
        render: function () {
            return (
                <div className="select">
                    <select ref="select"></select>
                </div>
            );
        }
    });

    return Select;
};

And when importing do something like this:

someFile.jsx

import React from 'react';
var Select = require('select')(React);

This would prevent the child component from having it's own React dependency.

sdoomz commented 8 years ago

I've installed react-select 1.0.0-rc.1 and it works fine for me. Version 1.0.0-rc.2 still cause 'Invariant Violation' error.

ZLester commented 7 years ago

@nburwell – Same setup as you and I'm running into the same issue. Did you ever discover a fix for this?

PendletonJones commented 7 years ago

We had this same issue but found a fix that has not been mentioned thus far. In our webpack setup we had a DLLs config with several entry points that was responsible for outputting 5-6 DLLs to be referenced in the main config. 'react-select' was in one and 'react-modal' was in another. Upon further inspection I realized that each of the DLL bundles was getting it's own copy of react. The bug only surfaced when a react-select box was nested inside of a react modal, but both libraries worked independently.

Solution was to have a multi-layered dll build process where a dll bundle containing just react and friends is created first, then referenced by the "level 2" dll bundles that contain things like react-select, then all the resulting dll bundles are referenced by the main build file.

Use the webpack analyze tool to inspect the stats from your bundles, it should provide some insight into how and why webpack is inserting multiple bundles.

Another solution that has worked in the past for me with the 'multiple copies of react' issue is to use the resolve section of the webpack config to point to a particular single copy of react.

seanriordan08 commented 7 years ago

I hit this when implementing browserify-rails. Defining const ReactCSSTransitionGroup = React.addons.CSSTransitionGroup; in your component while also declaring import ReactCSSTransitionGroup from "react-addons-css-transition-group" will throw it.

ritikama commented 7 years ago

I had

in my HTML file. I deleted these lines and it worked

marcellodesales commented 7 years ago

Should I give up???

I spent a couple of hours building this use case in isolation and after that, I decided the release a reusable component. However, after hours and hours and days trying to get this to work I'm finally in the step of making a decision...

I based my example on the sample from http://jedwatson.github.io/react-select/.

Running in isolation: Works

screen shot 2017-05-13 at 1 19 26 am

Running as a Shared Component

The component above then was placed in an isolated NPM Module/component and published to our private NPM registry. Then, when trying to see the component, I get the following error...

screen shot 2017-05-13 at 1 18 38 am

Running as a Share Library: Arrows keys partially work...

As a consequence, the UI can't render the properties right, but I can still use the up-down arrows to select my options, but without the nice UI experience...

screen shot 2017-05-13 at 1 18 49 am

Still work although it does not render properly..

screen shot 2017-05-13 at 1 27 11 am

Events don't work anymore

screen shot 2017-05-13 at 1 27 58 am

No duplicate react Dependency

$ npm ls | grep react@
npm info it worked if it ends with ok
npm info using npm@4.2.0
npm info using node@v7.9.0
│ │ ├─┬ babel-preset-react@6.16.0
│ └─┬ redbox-react@1.3.6
├─┬ eslint-plugin-react@6.10.3
├─┬ react@15.4.2
npm info ok
kutyel commented 7 years ago

I had this issue for weeks and just installed the latest version of react select 1.0.0-rc.4 and now everything works! 🎉 🎉 🎉 Huge thanks, @JedWatson!

warrenca commented 7 years ago

After weeks of digging, the root cause of my issue is with http://fb.me/react-warning-keys. Had a lot of trial and error by removing codes/debugging but Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs was solved by fixing react-warning-keys. Just sharing as this might help other people.

Sarkany-Adrian commented 7 years ago

@cubbuk's suggestion worked for me. The way I ended up with 2 copies of react was by debugging and rebuilding the react-select within node_modules of my project, in order to rebuild I ran npm i in /node_modules/react-select which installed a new copy of react. Hope this is helpful for anyone else.

JedWatson commented 7 years ago

I'm going to close this, as it's not really a react-select issue (and almost always related to having two copies of react loaded). Some great causes and solutions above 👍