mui / material-ui

Material UI: Ready-to-use foundational React components, free forever. It includes Material UI, which implements Google's Material Design.
https://mui.com/material-ui/
MIT License
91.86k stars 31.57k forks source link

you have multiple copies of React loaded #2818

Closed iceafish closed 8 years ago

iceafish commented 8 years ago

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.

neenaoffline commented 8 years ago

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

newoga commented 8 years ago

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

mlarcher commented 8 years ago

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.

newoga commented 8 years ago

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

mlarcher commented 8 years ago

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;
newoga commented 8 years ago

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

newoga commented 8 years ago

@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?

mlarcher commented 8 years ago

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

newoga commented 8 years ago

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

crantila commented 8 years ago

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!

alitaheri commented 8 years ago

@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?

mlarcher commented 8 years ago

@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

crantila commented 8 years ago

@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?

MayasHaddad commented 8 years ago

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!

MayasHaddad commented 8 years ago

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

oliviertassinari commented 8 years ago

React should be removed from the dependencies of the lib.

What do you mean?

MayasHaddad commented 8 years ago

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

MayasHaddad commented 8 years ago

*in my local dep tree

alitaheri commented 8 years ago

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

neenaoffline commented 8 years ago

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 < notifications@github.com> 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

oliviertassinari commented 8 years ago

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?

MayasHaddad commented 8 years ago

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

ahmadferdous commented 8 years ago

@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
├─┬ material-ui@0.14.2
│ └── react@0.14.6 
└── react@0.14.3 

$ 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!

dagatsoin commented 8 years ago

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

djalmajr commented 8 years ago

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

c0debreaker commented 8 years ago

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?

gilnahmias commented 8 years ago

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 -- react@0.14.7.

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.

ajsharp commented 8 years ago

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.

mlarcher commented 8 years ago

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.

ajsharp commented 8 years ago

@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 notifications@github.com 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 .

oliviertassinari commented 8 years ago

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.

mlarcher commented 8 years ago

@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 ?

cjose3 commented 8 years ago

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.

felipethome commented 8 years ago

@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

alitaheri commented 8 years ago

: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!

ir-fuel commented 8 years ago

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

felipethome commented 8 years ago

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

alitaheri commented 8 years ago

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/...')!

mbrookes commented 8 years ago

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

alitaheri commented 8 years ago

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.

felipethome commented 8 years ago

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.

alitaheri commented 8 years ago

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

felipethome commented 8 years ago

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

mbrookes commented 8 years ago

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.

felipethome commented 8 years ago

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.

peter4k commented 8 years ago

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.

mdarif commented 8 years ago

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'),
    }
apires commented 8 years ago

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.

haradakunihiko commented 8 years ago

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

mlarcher commented 8 years ago

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