Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReactMount: Two valid but unequal nodes with the same %s: %s #1400

Closed
syranide opened this issue Apr 11, 2014 · 32 comments
Closed

ReactMount: Two valid but unequal nodes with the same %s: %s #1400

syranide opened this issue Apr 11, 2014 · 32 comments

Comments

@syranide
Copy link
Contributor

https://github.com/facebook/react/blob/master/src/browser/ui/ReactMount.js#L81

It seems this is mainly the cause of invalid nesting of tags, <a><div /></a>, <table><tr></tr></table>, etc. I know there are some issues/PRs regarding this already but AFAIK they're trying to solve/detect it, it seems reasonable to just improve this (very non-informative) error message in the meantime.

PS. I've probably seen 2-3 people get bitten by it myself now that I think about it.

@sophiebits
Copy link
Collaborator

Do you have a repro? I don't think invalid nesting should cause this error.

@syranide
Copy link
Contributor Author

@spicyj Had a debugging session with skrebbel on IRC who encountered that error, turns out that he had <a><div /></a> and his browser turned it into <a /><div /><a /> and I assume React sometimes happened upon the second <a /> and found that it was not the element it was expecting (i.e, the first).

@sophiebits
Copy link
Collaborator

I don't believe browsers will do that for <a> (though they will if there are nested links). But I'm confused because I don't believe the newly-created elements will have data-reactid attributes at all.

@sophiebits
Copy link
Collaborator

Here's a demo showing that data-reactid shouldn't end up duplicated in that case:

http://jsbin.com/racecimo/1/edit

Let me know if you see otherwise.

@syranide
Copy link
Contributor Author

Reproduced it with:

http://jsfiddle.net/kb3gN/1874/

(i.e, yes you shouldn't do that, but it may still make sense to warn that it could be the cause)

@sophiebits
Copy link
Collaborator

Curious, thank you.

@syranide
Copy link
Contributor Author

Same issue:

#1436

@sophiebits
Copy link
Collaborator

Another possible cause of this error (just writing here for posterity):

React receiving events on elements that have been removed from the DOM. This shouldn't happen unless there is a bug in React; it happens in 0.9 and 0.10 due to a React bug. The issue has been fixed in master (in c62c2c5 and 3e34739) and will be in the next release.

@sophiebits
Copy link
Collaborator

See also #101.

@yoshuawuyts
Copy link

I just ran into this issue, it was indeed caused by invalid nesting, e.g.

<a>
  <div>
    <a></a>
  </div>
</a>

@syranide
Copy link
Contributor Author

Some love for #1987 perhaps :)

@hkairi
Copy link

hkairi commented Jan 16, 2015

Hi

I have the same error message. I have mounted 2 React component on 2 different #div element with different ids.

I was trying to have 2 different components doing different things.

@maciek-codes
Copy link

I believe I hit the same issue. I have two components in two different divs, they don't share common root. I create some components dynamically and end up with same ids. The set up is similar to this, but I cannot reproduce this outside my code.

@syranide
Copy link
Contributor Author

syranide commented Feb 4, 2015

@macqm Are you pre-rendering and perhaps rendering the same static markup to two different places?

@maciek-codes
Copy link

@syranide: I wasn't prerendering. I now tried to create the same component in same place where I create the element and I had same React class in a different module, loaded by require(...) with Browserify.

The class I created locally works just fine. When I load exact same module via Browserify, it does not work. Here's an illustration:

// Require apps
var Loaded = require('../components/widget/widget');
var Widget = React.createClass({
  //...
});

And now this works:

// Create react component from class
var component = React.createElement(Widget);
React.render(Widget, _windows[title].$content.get(0));

But loading same React class via Browserify causes an issue:

// Create react component from class
var component = React.createElement(Loaded);
React.render(component, _windows[title].$content.get(0));

I now get different error (I missed the moment it changed, but code looks almost identical):
Uncaught Error: Invariant Violation: findComponentRoot(..., .0.0.1): Unable to find element. This probably means the DOM was unexpectedly mutated

@syranide
Copy link
Contributor Author

syranide commented Feb 5, 2015

@macqm Find the reactID mentioned, it's most likely due to invalid nesting <p><p /></p> and things like that.

@maciek-codes
Copy link

@syranide Ooops. I had a div nested in another div. I believe that caused the issue. So I am back to original react-id error. It looks like I was wrong about the browserify. It doesn't seem to matter now.

This is the code I am using to create a widget class:

var Widget = React.createClass({
  getInitialState: function() {
    return {
      text: ""
    }
  },
  render: function() {
    return (
      <div className="widget">
          <h1>Widget</h1>
          <input className="widget-input" value={this.state.text} onChange={this.handleChange} />
          <p>{this.state.text}</p>
      </div>
    );
  },

  handleChange: function(e) {
    this.setState({text: e.target.value });
  }
});

And then I try to initialize the widget in a floating window (created using Ventus library):

// Create react component from class
  var component = React.createElement(Widget);

  React.render(component, _windows[title].$content.get(0));

where $contentis DOM element of the 'floating' window.
And as soon as I focus on the input, I receive the following error:

Uncaught Error: Invariant Violation: ReactMount: Two valid but unequal nodes with the same `data-reactid`: .0.1

Indeed, the newly created element gets assigned react-id of 0.0.

@syranide
Copy link
Contributor Author

syranide commented Feb 5, 2015

@macqm Do you have any repro I could look at? I'm assuming it's the external library that is mucking with the DOM. PS. Nesting divs is fine, p is not, same with div inside p, etc.

@maciek-codes
Copy link

@syranide: I was trying to reproduce the problem and than I noticed that I was loading require('react') and require('React'). I believe for some reason I ended up with two 'instances' of React in my app - should that be possible?
I need to investigate why the capital React worked for browserify (I am using reactify too). So no issue any more. Thanks for help!

@syranide
Copy link
Contributor Author

syranide commented Feb 5, 2015

@macqm That's a common issue on non-linux environments, case-insensitive filesystems and a bundler which doesn't warn. :)

@eugene1g
Copy link

eugene1g commented Feb 7, 2015

I encountered the same message with the same root problem - I included two independently webpack'ed bundles, and each one had a copy of react. The two bundles seemed to work (by some miracle), but I did get the error message about unequal nodes. Consolidating down to a single copy of React resolved the problem (thank you @macqm for the tip off).

I wonder if there is any way to catch this scenario within React, and include a warning that multiple versions of React may be present - this would go nicely along with the other very useful and helpful error descriptors!

@cmwelsh
Copy link

cmwelsh commented Mar 30, 2015

Hit this one by rendering a component inside an anchor tag:

<a>
    <SidebarComponent />
</a>

...

SidebarComponent = React.createclass({
    render: function () {
        return (
            <a>
                ends up nested inside the other anchor tag and throw
                Invariant Violation
            </a>
        );
    }
});

Seems like there should be a way to detect these.

@syranide
Copy link
Contributor Author

@cmwelsh #3467 should help with that in the next release.

@petilon
Copy link

petilon commented May 16, 2015

This problem repros in react-0.13.3.js see: http://jsfiddle.net/wnv190n8/5/

@maciek-codes
Copy link

@petilon Seems to work if you move the event handler inside the component, see example

@petilon
Copy link

petilon commented May 17, 2015

@macqm moving the event handler to the .JSX file is not an option for me. The event handlers, controllers, models etc need to be in .TS (TypeScript) files, only the view can be in .JSX.

This seems like a serious bug that Facebook hasn't completely fixed... for more than a year.

@maciek-codes
Copy link

@petilon: Aside from the fact that it still is an issue to fix and it seems like your code should work, from what you say, your view is in a JSX file. I would argue that handling a click event is definitely something that belongs to the view - you are reacting to a UI element action. Perhaps a good solution for you is to add another event to your component, something like onBuyingInitiated that you can then handle in your controllers and it would be fired inside onClick in the JSX. The handler can be passed as a prop. This way you may trigger same 'business logic' in your controller on clicks, key downs etc.

@petilon
Copy link

petilon commented May 17, 2015

@macqm Thank you for the suggestion. Some people would argue that handling events (and changing the view in response) is the controller's responsibility. This isn't just a philosophical issue. From a practical point of view it makes sense to move as much code as possible to .TS files because TypeScript can perform error checking. (Note that Flow isn't available on Windows.) Nevertheless, your idea is useful as a temporary workaround, so thank you for that.

@sophiebits
Copy link
Collaborator

This error message can be caused by a number of things, which are mentioned in these comments. Many are due to invalid nesting which we now have a warning for in master.

@petilon The specific issue you mention is the same as #3790, where we're tracking it.

I'm going to close this issue; if anyone encounters this error with a new cause, please open more specific issues.

@kennethaasan
Copy link

I got the same issue as @eugene1g . I'm creating a widget system with React, and my solution was to check if window.React existed. Then use React.render and React.unmountComponentAtNode from window.React if it exists:

const React = window.React || require('react');

@sksallaj82
Copy link

I'm getting this error when using react-bootstrap ui components. I'll be as descriptive as I can as I'm not allowed to show much code:

I added two ReactBootstrap.Buttons with a text that should dynamically change. So I have something that looks like this:

render: function(){
    return(
<div>    
    <CustomModal {...this.props} 
                show={this.state.showLabelModal} 
                onHide={this.onCloseModal} />
    <table>
        <tr>
            <th>
                <ReactBootstrap.Button bsStyle="default" onHide={this.onHideModal} onClick={this.openModal} style={{width:'100%'}}>
                    {this.state.Value1}</span>
                </ReactBootstrap.Button>
            </th>
            <th>
                <ReactBootstrap.Button bsStyle="default" onHide={this.onHideModal} onClick={this.openModal} style={{width:'100%'}}>
                     {this.state.Value2}</span>
                </ReactBootstrap.Button> 
            </th>
        </tr>
    </table>
</div>); }

On the Modal, I have two select boxes. Each select box is supposed to be representing the button it will change. So the first select, when you change it, should update the first button's text, if you change the second select, it should update the second button's text.

Notice, the modal is a child and the render function shown above is the wrapper that contains the modal and the table element. To make sure the state changes, the modal element makes a callback to the parent's function which does a setstate on Value1, Value2 (based on the select drop downs on the modal popup).

What happens: if you click the first button, the popup that shows both dropdowns will be displayed, if you change the 1st dropdown, only the 1st button's text will change. If you change the 2nd dropdown, the 2nd button DOESNT change.. and when you click on it.. it gives:

react-0.13.3.js:18472 Uncaught Error: Invariant Violation: ReactMount: Two valid but unequal nodes with the same data-reactid: .1.1.0.1.3.0

If you refesh the page, and repeat the steps, the second button opens the modal, the second drop down will work.. but the first drop down doesnt.. and if you close the modal and try to open it again from the 1st button.. the same error occurs:

Uncaught Error: Invariant Violation: ReactMount: Two valid but unequal nodes with the same data-reactid: .1.1.0.1.2.0\

I believe this ONLY happens when you involve states and dynamic ui interactivity. When something gets mounted with the state of the value you pass in, and you make a dynamic change to it, the mounted value will remain, as react doesn't believe this is the element that needs to be changed, and when you re-render it makes another copy on top of it (with the same id), but with a different value. So the garbage collection needs to be handled properly when you rerender. In my case this is a typical child-to-parent communication.

@sksallaj82
Copy link

Able to fix.. I changed

<ReactBootstrap.Button>{this.state.Value1}</ReactBootstrap.Button>

and just made it as a regular html:

<input type=button" className="btn btn-default" value="{this.state.Value1} />

So yes, it has something to do with children nodes and the depth of a component. In my case, a react component that had children.

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

No branches or pull requests

10 participants