Material-ui: you have multiple copies of React loaded

Created on 7 Jan 2016  Â·  62Comments  Â·  Source: mui-org/material-ui

version 0.14.1 produces this error:
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).

If remove node_modules/material-ui/node_modules/react,the error isn't present.

Most helpful comment

@oliviertassinari @newoga @alitaheri
I had the same issue today and I never had react installed inside material-ui package. So I discovered that is another thing that can cause this problem and it is something that material-ui can not solve (and is not its faulty). A lot of people normally bundle react in a different file from the bundle with their application code. The problem is that certain react add-ons and react utils are just a code like this:

module.exports = require('react/lib/ReactTransitionGroup');

And if we look at the code of the required module above we find a statement like this:

var React = require('./React');

It turns out that _./React_ is actually the entry point of the react package. In others words, some React modules import React again from inside. So if you don't declare also the add-ons that have this kind of declaration as externals from your application bundle and put them together with the bundle containing React, browserify (and probably webpack too) will import the React code again, so you end up with multiple copies.

I will try to make it clear because it is difficult to explain:
Make React an external resource in browserify with b.external('react') or in webpack with externals: {'react': 'react'} will not have any effect over an import like: var React = require('./React');

Demo

All 62 comments

Happens while using DropDownMenus too. Removing node_modules_material-ui/node_modules/react helps avoid the error as well.

@iceafish @neenaoffline Are you having this issue only on 0.14.1 and not 0.14.0? Can you show me which code is causing the error or what component it is complaining about?

This might be related to #2802.

If one of are able to try what's in master, that would be helpful too.

I am facing the same error message in 0.14.2 with the Datepicker component (in node 4.2.3/npm 2.14.7).
I am using ES6 imports syntax, and I believe https://github.com/callemall/material-ui/issues/2802 could be the root cause of the issue, but installing babel-plugin-add-module-exports and pluging it to my browserify bundle task didn't seem to help.
I have built was is currently on material-ui's master branch and got the same issue.
Please let me know if I can provide more info to help investigate.

@mlarcher I tried writing a test DatePicker on 0.14.2 and it looks like its working on my side. Are you getting an error on import? Or on render? Could you show me your import statement?

Also you shouldn't need babel-plugin-add-module-exports in your project (or more specifically you shouldn't need it for material-ui components). We already include it as part of the material-ui build in 0.14.2.

Maybe try deleting your node_modules and reinstalling too.

I already tried deleting node_modules and reinstalling, with no luck.
Here is the complete error output:

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).

invariant @ invariant.js:39
ReactOwner.addComponentAsRefTo  @ ReactOwner.js:67
attachRef @ ReactRef.js:23
ReactRef.attachRefs @ ReactRef.js:42
attachRefs  @ ReactReconciler.js:21
assign.notifyAll  @ CallbackQueue.js:65
ON_DOM_READY_QUEUEING.close @ ReactReconcileTransaction.js:81
Mixin.closeAll  @ Transaction.js:202
Mixin.perform @ Transaction.js:149
Mixin.perform @ Transaction.js:136
assign.perform  @ ReactUpdates.js:86
flushBatchedUpdates @ ReactUpdates.js:147
wrapper @ ReactPerf.js:66
NESTED_UPDATES.close  @ ReactUpdates.js:45
Mixin.closeAll  @ Transaction.js:202
Mixin.perform @ Transaction.js:149
assign.perform  @ ReactUpdates.js:86
flushBatchedUpdates @ ReactUpdates.js:147
wrapper @ ReactPerf.js:66
Mixin.closeAll  @ Transaction.js:202
Mixin.perform @ Transaction.js:149
ReactDefaultBatchingStrategy.batchedUpdates @ ReactDefaultBatchingStrategy.js:62
enqueueUpdate @ ReactUpdates.js:176
enqueueUpdate @ ReactUpdateQueue.js:24
ReactUpdateQueue.enqueueCallback  @ ReactUpdateQueue.js:108
ReactComponent.setState @ ReactComponent.js:67
openDialog  @ date-picker.js:244
(anonymous function)  @ date-picker.js:273
setTimeout (async)    
_handleInputTouchTap  @ date-picker.js:272
ReactErrorUtils.invokeGuardedCallback @ ReactErrorUtils.js:71
executeDispatch @ EventPluginUtils.js:79
executeDispatchesInOrder  @ EventPluginUtils.js:102
executeDispatchesAndRelease @ EventPluginHub.js:43
executeDispatchesAndReleaseTopLevel @ EventPluginHub.js:54
forEachAccumulated  @ forEachAccumulated.js:23
EventPluginHub.processEventQueue  @ EventPluginHub.js:259
runEventQueueInBatch  @ ReactEventEmitterMixin.js:18
ReactEventEmitterMixin.handleTopLevel @ ReactEventEmitterMixin.js:34
handleTopLevelWithoutPath @ ReactEventListener.js:93
handleTopLevelImpl  @ ReactEventListener.js:73
Mixin.perform @ Transaction.js:136
ReactDefaultBatchingStrategy.batchedUpdates @ ReactDefaultBatchingStrategy.js:62
batchedUpdates  @ ReactUpdates.js:94
ReactEventListener.dispatchEvent  @ ReactEventListener.js:204

Error seems to be on render (but I'm not utterly sure about that).
Here is what the usage looks like:

import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl';
import DatePicker from 'material-ui/lib/date-picker/date-picker';
// injectTapEventPlugin needs to be called for datepicker to work!
import injectTapEventPlugin from 'react-tap-event-plugin';

injectTapEventPlugin();

class BoxedInput extends Component {

  constructor() {
    super();
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(e) {
    e.preventDefault();
    this.props.onAction();
  }

  render() {
    var actionButton = !this.props.onAction ? null : (
      <button
        type="button"
        className="boxedInput_button"
        onClick={this.handleClick}
      >
        <FormattedMessage id={this.props.actionText || 'boxedInput_defaultActionMsg'}/>
      </button>
    );

    var boxedInputLabel = !this.props.label ? '' : (
      <span className="boxedInput_labelText">
        <FormattedMessage id={this.props.label}/>
      </span>
    );

    const input = this.props.type !== 'date' ? (
      <input
        type={this.props.showPassword ? 'text' : this.props.type}
        placeholder={this.props.placeholder}
        className={`boxedInput ${!this.props.type ? '' : `boxedInput--${this.props.type}`}`}
        {...this.props.field}
      />
    ) : (
      <DatePicker
        hintText={this.props.placeholder}
      />
    )

    return (
      <div
        className={`boxedInputWrapper ${!this.props.type ? '' : `boxedInputWrapper--${this.props.type}`} ${this.props.customClass || ''} `}
      >
        <label className="boxedInput_label">
          {boxedInputLabel}
          {input}
          {actionButton}
        </label>
      </div>
    );
  }
}

BoxedInput.displayName = 'BoxedInput';


BoxedInput.propTypes = {
  onAction: PropTypes.func,
  actionText: PropTypes.string,
  customClass: PropTypes.string,
  placeholder: PropTypes.string,
  type: PropTypes.string,
  label: PropTypes.string,
};

export default BoxedInput;

@mlarcher Thanks for copying the code. Could you try this as your import instead?

import {DatePicker} from 'material-ui/lib/date-picker';

The DatePicker component isn't currently default exported, not sure when that was changed...

Edit: Actually, your code should work. Let me look into this some more.

@mlarcher I can't reproduce this. I'm not having a problem importing date-picker in my projects in 0.14.2 with your same import statement. The docs are importing the date-picker the same way too.

The biggest difference is I (or the docs) don't use browserify. Would you be able to put a sample reproducible example on github somewhere that I can clone and try?

@newoga: here is a stripped down version that shows the bug :
test.zip

@mlarcher I'd recommend creating a project where your app.jsx is simply something like this:

import React from 'react';
import ReactDOM from 'react-dom';
import DatePicker from 'material-ui/lib/date-picker/date-picker';
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();

ReactDOM.render(
  <DatePicker />,
  document.getElementById('mainContainer')
);

I did that in your project an am still having your problem. More specifically, the component renders, and this error logs to console when you click the component and the dialog appears:

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

I didn't identify the root cause, but I'm not able to reproduce this in my webpack based projects. I'm also not able to reproduce this in this project's browserify example. I'd probably look very closely at your build process to make sure that your not doing anything that could accidentally be bundling React multiple times. You may be able to find some help of StackOverflow with browserify as I'm not too familiar with it.

Note: if you're going by the example, I just created #2857 so make sure to include those before running it.

Hi everyone. I was having this problem with my own project, but I solved it.

The problem is that "material-ui" 0.14.2 wants React "^0.14.6" but my project was using React 0.14.3, so npm installed an extra copy of React, just for material-ui.

When I upgraded my project to React 0.14.6, then reinstalled material-ui, npm used the top-level React as a "peerDependency." Now React is only loading once—problem solved!

@crantila That's really weird. Why did npm install a copy for material-ui? React is a peer dependency for material-ui. npm doesn't automatically install peer dependencies. what version of npm are you using?

@newoga There is indeed a problem with the way I generate the libs.js bundle. It may be due to the fact that the files in bundle.js are listed from the dependencies of my package.json, and even though 'material-ui' is an explicit dependency, 'material-ui/lib/date-picker/date-picker' isn't. Or maybe it is an issue with having react required by ES6 imports in my code and require() calls in meterial-ui. Anyhow, I'll have to find a better way to handle this kind of scenarios.

Still, when I stop excluding libs from the bundling task and load all js from the same bundle, I don't have the invariant error anymore, but now the calendar opens but doesn't have any content :

I guess it is another issue, though, so I'll check if it is already referenced and open a new ticket if it isn't.

Edit: Actually, this problem is just due to the way the datepicker resizes when chrome dev tools is opened. No biggies, even though it could be improved. Problem is fixed for me, thanks for your help @newoga

@alitaheri I'm using npm 2.14.12, which ships with the "stable" Node release. There's a warning about how peer dependencies won't be installed automatically, but it does still install them.


It seems like there are several different ways to cause multiple React versions to load, and they all result in material-ui not working. Would it be possible for material-ui to detect when this is happening, and to print a message in the console that contains a link to a (wiki?) page with more information about what might be causing the problem?

Please, React should be removed from the dependencies of the lib.

Check this excellent example of react-router

React is used as a devDependency instead.

Cheers for the good job you guys are doing!

P.S.
If you want to avoid dependency issues related to the react version used by material-ui, then use "peerDependencies" property as such

React should be removed from the dependencies of the lib.

What do you mean?

@oliviertassinari I had to remove react from within material-ui to get rid of "... or you have multiple copies of React loaded"

*in my local dep tree

With npm v3+ I never experienced this issue. Could you update your npm and try again?

React is only a devDependency in material-ui as well, but that causes the
conflict if you're using an older version of npm because it would install
two copies anyway without attempting to avoid duplication. I believe this
changed in npm 3.

https://github.com/npm/npm/blob/master/CHANGELOG.md
http://blog.npmjs.org/post/91303926460/npm-cli-roadmap-a-periodic-update

On Tue, Jan 12, 2016 at 11:23 AM, Ali Taheri Moghaddar <
[email protected]> wrote:

With npm v3+ I never experienced this issue. Could you update your npm and
try again?

—
Reply to this email directly or view it on GitHub
https://github.com/callemall/material-ui/issues/2818#issuecomment-170805616
.

neena

I was using npm 2 until recently and I had no issue. We declare react as a "dependency" at two places in our package.json.
Once as a peerDependency. This makes npm 2 installing react at the root node_modules, so that shouldn't be an issue.
We also declare it as a devDependency, that is just ignored during a npm install from your project directory.
How can we reproduce this issue?

I removed node_modules and reinstalled, everything is ok now.
I'll consider upgrading to npm3 though.

@oliviertassinari
I started my project with relay-starter-kit. At that time it used react and react-dom exact version 0.14.3. When I added module material-ui to my project, React Dev Tools (chrome extension) complained about multiple react versions being loaded. This is what I found when I checked:

$ npm list react
├─┬ [email protected]
│ └── [email protected] 
└── [email protected] 

$ node -v
v4.2.4
$ npm -v
2.14.12

When I upgraded to npm v3, the issue was tackled by npm itself by keeping a single version of react. However, as far as I know, relay is currently bound to npm v2. So a solution in material-ui with npm v2 would have been nice!

I am facing a similar problem with Meteor 1.3.beta4 and npm 2.14.14.

I also tried with NPM3 but when I launch the app the console tells me that 'react' can't be found even if it is included with meteor add react

I have a project called ui that uses material-ui as base, then I import the ui to another project. The error happens to me when I import certains components to my ui project:

captura1

captura2

captura3

captura4

When the size of the bundle increases like that, this error occurs.

The same to this components: ListItem, MenuItem, IconButton...

Tried the solution above by removing the node_modules/react inside material-ui and then restarted my application, it worked! Thanks a lot!

Now, if my officemates git clone my application and run npm install, their copy of material-ui will have a react. It's not a good idea to tell them "Hey, for now remove this directory". How should I update my project so that when material-ui is installed, it won't have the react node module?

Same issue here: npm 3.7.1, react ^0.14.0, material-ui ^0.14.4, webpack ^1.12.9
No node_modules in ./material-ui to delete even as a temp workaround.

npm list react yields -- [email protected].

Code calls:

import RaisedButton = require('material-ui/lib/raised-button');
import Dialog = require('material-ui/lib/dialog');
import FlatButton = require('material-ui/lib/flat-button');

The following webpack.config.js approaches failed:
1.

  externals: {
    "react": "react",
  }

2.

plugins: [
    new webpack.optimize.CommonsChunkPlugin("react", "react.bundle.js")
]

3.

resolve: {
        alias: {
            "react": __dirname + '/node_modules/react',
        }
    }

Symptoms: Upon build, an inflated bundle file is created containing react; In run-time, I get an error message: "addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component'srendermethod, or you have multiple copies of React loaded (details: https://fb.me/react-refs-must-have-owner)."

Any ideas? For now I'll take any workaround.

Upgrading to npm 3.7.1 fixed the issue for me. I agree, react should not be a dependency or peerDependency of this project due to the issues npm has with peerDependencies.

Anyone is working on the issue ?
material-ui insists on installing react 0.14.7 even though I already have react 0.14.6 in my project package.json, so we end up with two versions and errors in the console.

@mlarcher unfortunately the only "fix" is fixing how dependencies are done.
You're probably using a version of npm (less than 3) that installs peer
dependencies. If you upgrade to latest you can work around this issue
because material-ui's version of react won't get installed bc newer
versions of npm don't install peer deps.

I believe react should only be a Dev dependency. Peer dependencies are a
nightmare for users and should pretty much never be used IMO.
On Thu, Feb 11, 2016 at 1:13 AM mlarcher [email protected] wrote:

Anyone is working on the issue ?
material-ui insists on installing react 0.14.7 even though I already have
react 0.14.6 in my project package.json, so we end up with two versions and
errors in the console.

—
Reply to this email directly or view it on GitHub
https://github.com/callemall/material-ui/issues/2818#issuecomment-182775790
.

I believe react should only be a Dev dependency.

I'm not convinced https://github.com/rackt/react-redux/blob/master/package.json#L98.
I don't understand what's going on with npm@2. That used to work for me.

@ajsharp wht puzzles me is that react is already present at the same level as material-ui (so, as a peer), but npm still installs it (within the material-ui folder). Any idea why ?

The node engine for the RKS (in the yeoman generator) is:
"engines": { "node": ">=5.0 <6", "npm": ">=3.3 <4" }

I use:
"material-ui": "0.14.4", "react": "0.14.7",
and work fine.

@oliviertassinari @newoga @alitaheri
I had the same issue today and I never had react installed inside material-ui package. So I discovered that is another thing that can cause this problem and it is something that material-ui can not solve (and is not its faulty). A lot of people normally bundle react in a different file from the bundle with their application code. The problem is that certain react add-ons and react utils are just a code like this:

module.exports = require('react/lib/ReactTransitionGroup');

And if we look at the code of the required module above we find a statement like this:

var React = require('./React');

It turns out that _./React_ is actually the entry point of the react package. In others words, some React modules import React again from inside. So if you don't declare also the add-ons that have this kind of declaration as externals from your application bundle and put them together with the bundle containing React, browserify (and probably webpack too) will import the React code again, so you end up with multiple copies.

I will try to make it clear because it is difficult to explain:
Make React an external resource in browserify with b.external('react') or in webpack with externals: {'react': 'react'} will not have any effect over an import like: var React = require('./React');

Demo

:scream: :scream: My god, that's a great find!

@felipethome You think we should add that to our documentation? or should webpack/browserify do that? this is indeed a very hard problem to track down!

Had the same issue. Upgrading react to 0.14.7 solved it.

@alitaheri I believe we should add that to MUI documentation and you?
(and actually, I also think React should add that to theirs, like a tip saying some add-ons import React, but I don't think they will)

and you?

add that.. to me? :laughing:

I think this is a design issue with browserify and webpack. I mean if require('react') is external then so is require('react/lib/...')!

add that.. to me?

Well you already eat, sleep and breath React already, so why not? :laughing: I would suggest a tattoo, but that would make updates painful (literally!)

Well you already eat, sleep and breath React already, so why not?

:laughing: :laughing: :laughing:

I would suggest a tattoo, but that would make updates painful (literally!)

I could tattoo a link back to mui docs, the link won't need updates :laughing: :laughing:

@felipethome Would it make sense to put the tattoo *cough* issue on the webpack repo? I don't think this is hard to fix for them, but I believe it's a critical one.

I would suggest a tattoo, but that would make updates painful

:laughing: :laughing:

@alitaheri I can add of course, but I don't know exactly where do you want me to add that information, in the README?

Would it make sense to put the tattoo _cough_ issue on the webpack repo?

Maybe the first design flaw is from React, why their add-ons share the same respository of the React project?

I looked at browserify code, they could use require.resolve() with the externals declared by the user, that would externalize modules names and their main files, but then we start to have problems in other parts. I am still not sure if it is easy to solve or if they (webpack/browserify) will consider that an issue, but we can try.

Yeah... Maybe start with react first? I mean you are right that IS a flaw!

I actually did it 3 days ago, but they don't seem really worried in this issue

No guaranteeing it'll help, but you could try following up with a PR... there are usually less of those than issues, so they gate a bit more attention.

I can not send the right PR because it is a project level issue, but I can send one that makes sense so I can see what they think and if they consider I am wrong. But think about it, you are developing the project X and to develop X you are importing X.

It is likely your material ui dependency has a different react version than your react version. So that npm will let material-ui to load a different version.

Uninstalling and doing the fresh npm install works for me.

This is my package.json looks like:

{
  "name": "react-app",
  "version": "0.0.0",
  "description": "",
  "main": "webpack.config.js",
  "dependencies": {
    "axios": "^0.9.1",
    "babel-loader": "^6.2.0",
    "babel-plugin-add-module-exports": "^0.1.2",
    "babel-plugin-react-html-attrs": "^2.0.0",
    "babel-plugin-transform-class-properties": "^6.3.13",
    "babel-plugin-transform-decorators-legacy": "^1.3.4",
    "babel-preset-es2015": "^6.3.13",
    "babel-preset-react": "^6.3.13",
    "babel-preset-stage-0": "^6.0.14",
    "formsy-material-ui": "^0.3.8",
    "formsy-react": "^0.17.0",
    "history": "^1.17.0",
    "material-ui": "^0.14.4",
    "react-router": "^1.0.3",
    "webpack": "^1.12.14",
    "webpack-dev-server": "^1.14.0"
  },
  "peerDependencies": {
    "react": "^0.14.3",
    "react-dom": "^0.14.3",
    "react-tap-event-plugin": "^0.2.0"
  },
  "devDependencies": {},
  "scripts": {
    "dev": "webpack-dev-server --content-base src --inline --hot --host localhost --port 4444",
    "prod": "webpack --env=production"
  },
  "author": "",
  "license": "ISC"
}

Alternatively if you using webdev and then adding blow code, would resolve the issue.

  resolve: {
    alias: {
      react: path.resolve('./node_modules/react'),
    }

The issue for us is that we had shrinkwrapped 0.14.7 and material-ui 0.15-alpha-2 isn't shrinkwrapped so it pulled react 0.14.8.

Would be nice if the deps were shrinkwrapped or more specific about versions.

@mlarcher @ahmadferdous
maybe this will help.
https://github.com/npm/npm/pull/12290

@haradakunihiko: this issue is related to npm-shrinkwrap, which is not involved on the problematic scenario, so I wonder if it could work in our case. I should give it a try, but for now we moved to npm3 to avoid the issue.

Just to make it clear, our situation is the following:
We have a 0.14 version of React in our package.json and npm@2 installs a newer version of the same minor within node_modules/material-ui instead of aknowledging a peer dependency satifying material-ui's requirements is already present.

@mlarcher Actually, I'm definitely in the same situation, but with react-bootstrap. React-bootstrap has peer dependencies for react and it installs newer version of react inside react-bootstrap module.
And it is very likely because of shrink-wrap (https://github.com/npm/npm/issues/5135#issuecomment-207684987). This could happen also with material-ui.
I think this kind of issue is not caused by a single problem, but shrink-wrap with npm@2 would be one of the causes.
Anyway, updating npm to ver.3 would be the best solution (and sadly, I can not update for some reason...).

We were seeing these same issues while developing a common react components library that utilized Material UI. After trying many of the different solutions that were suggested, the following worked for us:

Adding below to our webpack config:

resolve: {
    alias: {
      react: path.resolve('./node_modules/react'),
    }
}

Thanks to @mdarif for the tip!

Making a alias solves my problem @cody-lettau @mdarif thanks anyways

@felipethome I'm having the same problem, specifying react as an external resource to browserify did not fix the import of ./React. How did you get around it? FYI I'm using grunt and browserify.

@arzavj I don't use grunt, but give a look at the gulpfile.js of this seed. Maybe it helps you.

Got it! Thanks!

@cody-lettau did you add that to the webpack config for the library, or for the project that uses that library?

@sunny-g It was added to the library we were building. This library utilized material-ui.

Thank you for the prompt response! I ended up using externals in the library's webpack.config.js and that fixed the error.

felipethome commented on 23 Feb
Thanks @felipethome for your comment and the github example, you solved my issue! It was the 'react-addons-transition-group' not being listed in the external dependencies (next to React, etc) for browserify. It's a bit scary that something can go this horribly wrong without clear indication of what the issue is. Thanks again!

My issue was a bit different. I had 2 different Webpack bundles and both were pulling in React. One of my NPM modules in the 2nd bundle did a require('react') and require('react-dom').

I fixed it by adding the following to my 2nd bundle's Webpack config

externals: {
  // Don't bundle react or react-dom
  'react': 'React',
  'react-dom': 'ReactDOM',
}

I had the same issue and i solved it by removing all the node modules and using yarn to install all the dependencies again.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pola88 picture pola88  Â·  3Comments

newoga picture newoga  Â·  3Comments

TimoRuetten picture TimoRuetten  Â·  3Comments

FranBran picture FranBran  Â·  3Comments

sys13 picture sys13  Â·  3Comments