Skip to content
This repository has been archived by the owner on Feb 6, 2023. It is now read-only.

Refs must have owner #296

Closed
masylum opened this issue Apr 12, 2016 · 44 comments
Closed

Refs must have owner #296

masylum opened this issue Apr 12, 2016 · 44 comments

Comments

@masylum
Copy link

masylum commented Apr 12, 2016

Hi,

I just wanted to try Draft.js and tried to drop the example in my application and I've got the https://fb.me/react-refs-must-have-owner issue.

I simplified a little bit my code, but looks something like this:

// ModalComposer.jsx
import React from 'react'
import { Editor, EditorState } from 'draft-js'

const ModalComposer = React.createClass({
  getInitialState () {
    return {
      editorState: EditorState.createEmpty()
    }
  },

  onChange (editorState) {
    this.setState({editorState})
  },

  render () {
    const { editorState } = this.state

    return (
      <div>
        <Editor
          editorState={editorState}
          onChange={this.onChange}
        />
      </div>
    )
  }
})

export default ModalComposer
// Modal.jsx
import { connect } from 'react-redux'
import ModalComposer from './ModalComposer.jsx'
import * as modalActions from '../../ducks/modals'
import React from 'react'

const Modal = React.createClass({
  propTypes: {
    dispatch: React.PropTypes.func.isRequired
  },

  onClickClose () {
    this.props.dispatch(modalActions.pop())
  },

  render () {
    return (
      <div>
        <button onClick={this.onClickClose}></button>
        <ModalComposer />
      </div>
    )
  }
})

export default connect()(Modal)

I get the following:

invariant.js:39 Uncaught 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

When I comment out the component ModalComposer (which is basically the draft-js one) I don't get this warning, so its not related to npm and dependencies.

Thanks in advance!

@hellendag
Copy link

I don't see any obvious problems with the code here.

At what point are you seeing this invariant? Immediately when the component renders?

@masylum
Copy link
Author

masylum commented Apr 14, 2016

I will try to debug it and isolate better the issue to give you better information

@apuntovanini
Copy link

apuntovanini commented Apr 22, 2016

+1 @masylum, same issue here, with super simple example

@apuntovanini
Copy link

@hellendag I see it when the component renders, no matter whether it is included in a more complex component or rendered simply

@hellendag
Copy link

@apuntovanini Can you provide a gist of your code? Are you seeing any issues with refs in the examples provided with the draft-js repo?

@mattmarcello
Copy link

I am seeing this issue with the most contrived example in both chrome and firefox.

Also, in more complex examples that involve unmounting of this component, i am seeing a removeComponentAsRefFrom(...) invariant.

import React, { PropTypes, Component } from 'react';
import {
  Editor,
  EditorState,
} from 'draft-js';

export default class MyEditor extends Component {

  constructor(props) {
    super(props);
    this.state = { editorState: EditorState.createEmpty() };
    this.onChange = (editorState) => this.setState({ editorState });
  }

  render() {
    const { editorState } = this.state;
    return <MyEditor editorState={ editorState } />
  }
}
ReactDOM.render(
  <MyEditor/>,
  document.getElementById('root')
);

@mattmarcello
Copy link

This issue was resolved for me by ensuring that I don't have multiple copies of React loaded.

@sophiebits
Copy link
Contributor

It's very likely that anyone else seeing this is also using multiple copies of React – probably one that Draft is using and one that the rest of your app is using. It's possible we could change Draft to use the function-style refs that can work around this problem, but you don't want multiple copies of React regardless because it's inefficient and can cause other problems like this.

@conor909
Copy link

The error message does mention that there is probably multiple versions of react. I'v tried a few suggestions around node package installs but I still get the error. Does this mean the Draft.js repo is not ready or is it something we can fix?

@sophiebits
Copy link
Contributor

@conor909 Can you gist the output of "npm ls"?

@conor909
Copy link

conor909 commented Jun 1, 2016

I'm using a windows terminal and not sure how else to log the full output to a file, I could only copy as far as windows will allow me to scroll back up: Does this help? https://gist.github.com/conor909/62080cc39472569316d3e2e87e455156

@bitmapdata
Copy link

I met this issue when i using a react-router delivered component.

...
ReactDOM.render((
  <Router history={browserHistory}>
    <Route component={App} path='/'>
      <Route path='login' component={LoginComponent}/>
      <IndexRoute onEnter={loginRequired} component={DraftComponet}/>
    </Route>
  </Router>
), document.getElementById('app'));

@hellendag hellendag added the meta label Jun 20, 2016
@jdu
Copy link

jdu commented Oct 5, 2016

I'm having this issue now in a simple use-case. Essentially, due to the structure of my application I load React and ReactDOM using script tags in the sites head tags. The reason being there are multiple client-side applications which depend on it and rather than bundling it into each application, it's easier to just include it in the page as a header script tag.

I tried rendering a simple Draft-js Editor using the exact same code as @mattmarcello above (minus the React imports as it's already in the DOM) within one of my client-side applications. If I do this, react complains about an Invariant Violation which seems to trace to there being multiple Reacts being loaded as mentioned above when Editor is used. Up until I imported Draft-js, this issue didn't exist, so it's directly correlated to Draft-JS.

Is there a way to specify Draft-JS's copy of React[DOM] to use so that it uses the already loaded modules instead of overriding the existing one?

@jdu
Copy link

jdu commented Oct 5, 2016

To mitigate this, I've gone through the entire draft-js lib folder and commented out all occurrences of imports of React and ReactDOM so that Draft-js doesn't override my already loaded React version.

I don't use any other react based plugins which is why I've not had this issue in the past. There must be some valid way to override the loading of react via require() or import in third-party libraries (not harping on you guys, it's just a general statement) as it essentially is making a design decision for you for how your application should be organized and how React should be loaded, which in my case, using require to import React and ReactDOM in every client-side application we have isn't a viable design decision as we have connection speed constraints and we need to aggressively browser cache as much as we can and reduce the application sizes down as lean as we possibly can.

@john-osullivan
Copy link

john-osullivan commented Oct 29, 2016

Running into this same issue when using https://github.com/draft-js-plugins/ . The issue seems to be that these Draft.js libraries are importing their own copy of React. Isn't this what npm's peerDependencies are for? If people are using Draft.js then they must already be using and loading React elsewhere, would moving "react" to the peerDependency list fix this issue?

Edit: I'm also using react-router to deliver the component tree that the Draft.js editor is eventually a child of.
Edit 2: On the other hand, running npm ls yields only one instance of React in my dependency tree. @bitmapdata , how'd you end up resolving this? Inspecting the internal instance shows that the component which should render the Draft.js input doesn't have an owner, and none of the children of the components rendered by react-router have owners either. The page component itself has an owner, but its child components don't. Did it end up being a react-router issue for you?

@saymy
Copy link

saymy commented Dec 2, 2016

+1

@uyson
Copy link

uyson commented Dec 13, 2016

  • 1

@FourwingsY
Copy link

I've found something weird.
if I use npm install draft-js --save, no error.
but yarn add draft-js, error occur.

@Darmikon
Copy link

Is any way to solve this problem?

@iPekka
Copy link

iPekka commented Feb 1, 2017

Having the same issue. I'm trying to use draft-js inside a third-party library of components (via npm).
Have you found any good solution ?

@flarnie
Copy link
Contributor

flarnie commented Jun 26, 2017

We just investigated a similar issue - #951 and were not able to reproduce the problem.

Sorry that this issue has gotten stale - wondering if folks are still running into this? Also if it's related to https://github.com/draft-js-plugins/ please file an issue there, thanks!

@jdu
Copy link

jdu commented Jun 26, 2017

We actually abandoned draft-js on this alone as it sort of broke everything when we tried to use it. It wasn't related to the plugins repo it was on import of draft-js.

I'm away until near week but I can give it a try then and see if the issue is still there for us and get back to you as we'd still like to use it.

@john-osullivan
Copy link

We abandoned it as well. I tried filing an issue at https://github.com/draft-js-plugins/ but didn't get anywhere. Not sure why it's so hard to reproduce on y'all's end. Maybe it's an npm vs. yarn issue? @jdu , which one are you all using?

@RyanCCollins
Copy link

RyanCCollins commented Jul 10, 2017

@flarnie, I am still running into this issue. Seems to be exactly the same as the others here. Is there a solution to this?

@jdu
Copy link

jdu commented Jul 10, 2017 via email

@flarnie
Copy link
Contributor

flarnie commented Jul 11, 2017

For more context - this error is almost always caused by having multiple copies of React loaded. That can easily happen if you are using npm. See https://facebook.github.io/react/warnings/refs-must-have-owner.html

We are going to improve the error messaging on the React side and come up with better documentation about how to avoid this problem.

Thanks everyone for the comments and info.

@flarnie
Copy link
Contributor

flarnie commented Jul 11, 2017

Also see this issue on React for tracking the improvements to the error message: facebook/react#9962

@jdu
Copy link

jdu commented Jul 11, 2017 via email

@flarnie
Copy link
Contributor

flarnie commented Jul 11, 2017

I'm looking for how to reliably reproduce this - can folks let me know what version of npm, react, and draft you are using? What does your package.json look like? Were you using yarn or just npm?

@john-osullivan
@jdu
@masylum
@iPekka

For now the way I'm reproducing this is by manually copying node_modules/react into node_modules/draft-js/node_modules/react.

@john-osullivan
Copy link

My setup is likely different from these other people, but like @jdu said, it boils down to draft-js loading its own React. Using plenty of other React plugins, this is the only one giving me the issue.

Our app is built on Meteor, so we're using the Meteor+NPM integration which gives us npm@4.6.1. react@15.5.4, draft-js@0.9.1. We abandoned draft-js a pretty long time ago, as there were more important issues and we couldn't wait on this bug -- other people will likely have a more representative setup for the current versions.

Are all of the draft-js devs using yarn? Can't wait for the moment when yarn users start causing bugs for npm users in the name of better guarantees :P

@jdu
Copy link

jdu commented Jul 11, 2017

I'm seeing if I can reproduce it in a simple example now, not sure if it still happens as we encountered the issue quite a while ago but will post up a repo if I can get it to happen.

@jdu
Copy link

jdu commented Jul 11, 2017

Right, I've reproduce this @flarnie in a simple setup, the repo is here https://github.com/jdu/draft-js-borked if you pull that and run ./server.sh and go to localhost:8000 you should get the error.

The package.json in the repo is what's been used to build it, it use browserify and babel, to build it again you can run make dev.

Sorry its not a very nodejs build system but I did it quickly by replicating our old build pipeline from 6+ months ago.

The web server is just a python simpleHTTPServer.

If I run this in Chrome I get the error

react-dom.js:18125 Uncaught Error: 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).
    at invariant (react-dom.js:18118)
    at Object.addComponentAsRefTo (react-dom.js:10760)
    at attachRef (react-dom.js:11695)
    at Object.ReactRef.attachRefs (react-dom.js:11714)
    at ReactDOMComponent.attachRefs (react-dom.js:11529)
    at CallbackQueue.notifyAll (react-dom.js:959)
    at ReactReconcileTransaction.close (react-dom.js:11408)
    at ReactReconcileTransaction.closeAll (react-dom.js:14826)
    at ReactReconcileTransaction.perform (react-dom.js:14773)
    at batchedMountComponentIntoNode (react-dom.js:9794)

The key difference here is that react isn't imported into the app.js bundle, it's referenced from the index.html file.

@gaearon
Copy link
Contributor

gaearon commented Jul 12, 2017

@jdu In your example the app code uses a global React and ReactDOM from separate vendor files, but then Draft.js uses the react from npm. This is what's causing the issue. You can either change the app to use React from npm too, or you can change the browserify setup to shim react and react-dom npm packages with global variables. Does this make sense? This doesn’t sound very specific to Draft—I’d expect you to have this issue with every npm library of React components.

@gaearon
Copy link
Contributor

gaearon commented Jul 12, 2017

@jdu I sent a PR to fix the build in your example: https://github.com/jdu/draft-js-borked/pull/1

I hope it helps others, but if your setup is different, please share it and we’ll try to fix them too.

There is another way to fix it (by telling browserify that it shouldn’t bundle react and react-dom from npm, and should instead use the globals). I’m not sure which browserify option does that.

@jdu
Copy link

jdu commented Jul 12, 2017

@Gaeron Thanks for the pull request, we use a shim now in our current build (we swapped to webpack a while back) but still don't import any third-party react components, but at the time we encountered the problems with draft-js, draft-js was the only react library we used (everything was built from scratch). In my original comments, the reason we were loading the react libs in the html file was because we have around 20+ client-side applications loaded at different URIs using the same index and built on react, so we load React/ReactDOM and some other common libraries from the index rather than import them into the apps themselves to reduce the client app sizes and allow users to cache those libraries.

At the time we'd only been using React for a few months and it wasn't clear at the time how to overcome this, the key here being we're commenting on an issue from Oct of last year, plenty of change has happened in React (and it's associated build processes) since that time and we've got months more experience using the framework versus then and understand better how to handle things like this.

I think at least for us, if we imported draft-js into our current builds it would probably be fine, it was just a the time of this issues creation and the subsequent initial comments everything was a lot newer and it wasn't as easily understandable why importing a library would overwrite something you had already declared in your application, now you see loads of stack overflow questions and other sites posts which boil down to having two reacts loaded in a single react application, whether better error messages as @flarnie talked about are the key I'm not really sure, it seems (to me) that if this is as wide-spread of a mistake/stumbling block as it seems to be that React should be capable of detecting a pre-existing instance of itself and not to overwrite while at the same time issue a warning in the console to the effect that a component tried to load a secondary copy of React. But that's on reacts side and nothing really to do with draft-js.

Thanks for having a look.

@davidbarker
Copy link

davidbarker commented Jul 19, 2017

I seem to be having the same problem. I'm not sure when it started, but on the production server I was getting the error, but my local was fine. The only difference being that production was using yarn but local was using npm install. I actually have no idea what I did, but production started working (all I did was clear out my local node_modules directory, and ran yarn, and committed and pushed the lock file to production).

However, I checked my local today and that was broken (although I'm not sure how as it was working fine when I went to bed last night!)

So, I cleared out my node_modules directory again and ran npm install and my local is now working fine.

I can't figure out a) why it suddenly broken on production, and b) why there's a discrepancy between production and local. Presumably yarn vs. npm install is the issue? I'm now worried that my next push to production will break production again.

@gaearon
Copy link
Contributor

gaearon commented Jul 19, 2017

Run npm ls react to see where React is in the tree. If you have it there twice that's the problem.

@davidbarker
Copy link

davidbarker commented Jul 19, 2017

/usr/local/var/www/
├─┬ linkifyjs@2.1.4
│ └── react@15.6.1  deduped
└── react@15.6.1 

Does deduped mean that this isn't an issue?

@john-osullivan
Copy link

Quick update, I was able to resolve this error by stripping out a deprecated library which we were using to connect Meteor to react-router on the server. Just in case one of the other 42 people with that library installed run across this, reactrouter:react-router-ssr is super broken -- ditch it!

@flarnie
Copy link
Contributor

flarnie commented Aug 11, 2017

Hi all - hopefully we have enough info here to help anyone who runs into this debug their situation to remove the extra copies of React they may have loaded. For now I'm closing this since it is not a bug in Draft and there are no actionable items on our side.

Thanks everyone for talking through the resolution of several cases of the issue!

@flarnie flarnie closed this as completed Aug 11, 2017
@flarnie flarnie mentioned this issue Aug 16, 2017
14 tasks
@apuntovanini
Copy link

I'm sorry to come back on this, but yes, multiple copies of React could be the issue (which I don't have), though many other react packages work either way. I had the same issue with another library, namely https://github.com/vlad-ignatov/react-numeric-input, which lists react as a devDependency but uses string refs. I really thing that string refs are the very reason why it doesn't work for some environments.
Couldn't #925 or similar PR fix this?

@flarnie
Copy link
Contributor

flarnie commented Sep 23, 2017

I'm happy to accept PRs updating the ref syntax, but I also think it's usually a mistake when someone ships two copies of React, so it has been convenient in a way that this warning pops up.

Also just found one of the Draft.js examples reliably reproduces this warning, and it looks like a bug with yarn to me. Opened an issue, so anyone else running into this might check there. yarnpkg/yarn#4532

@williamlifaith
Copy link

williamlifaith commented Sep 28, 2017

I met this issue when I use Material UI.'Element ref was specified as a string (clickAwayableElement) but no owner was set. You may have multiple copies of React loaded. (details: https://fb.me/react-refs-must-have-owner).'Does anyone has the solution?

@sophiebits
Copy link
Contributor

@williamlifaith There are many comments on this issue describing this issue in detail.

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

No branches or pull requests