22

I am getting the following error when my react component is re-rendered after a click event:

Uncaught Error: Invariant Violation: processUpdates(): Unable to find child 2 of element. This probably means the DOM was unexpectedly mutated ...

This only happens when my table has a different number of rows than the previously rendered version. For example:

/** @jsx React.DOM */

React = require('react');

var _ = require("underscore");

var testComp = React.createClass({

  getInitialState: function () {
    return { 
      collapsed: false
    };
  },

  handleCollapseClick: function(){
    this.setState({collapsed: !this.state.collapsed});
  },

  render: function() {

    var rows = [
      <tr onClick={this.handleCollapseClick}><th>Header 1</th><th>Header 2</th><th>Header 3</th></tr>
    ];

    if(!this.state.collapsed){
      rows.push(<tr><th>Row1 1</th><th>Row1 2</th><th>Row1 3</th></tr>);
    }

    rows.push(<tr><th>Footer 1</th><th>Footer 2</th><th>Footer 3</th></tr>);

    return  <div>
                <table>
                    {rows}
                </table>
            </div>
  }

});

module.exports = testComp

If I render different content, but with the same number of rows, I don't get the error, so if I update the if statement to:

if(!this.state.collapsed){
  rows.push(<tr><th>Row1 1</th><th>Row1 2</th><th>Row1 3</th></tr>);
}else{
  rows.push(<tr><th>Row2 1</th><th>Row2 2</th><th>Row2 3</th></tr>);
}

... everything works.

Do I need to force react to re-render the entire component in this case, instead of just the 'changed' elements?

koosa
  • 2,966
  • 3
  • 31
  • 46
  • This could be because you are not giving the elements inside the array unique `key`s. See http://facebook.github.io/react/docs/multiple-components.html , dynamic children. – Felix Kling Nov 01 '14 at 13:48
  • Even with keys added I see the same result... – koosa Nov 01 '14 at 13:55
  • Actually, adding keys means that even when using the same number of elements I still get the above error... – koosa Nov 01 '14 at 13:59
  • possible duplicate of [Uncaught Error: Invariant Violation: findComponentRoot(..., ...$110): Unable to find element. This probably means the DOM was unexpectedly mutated](http://stackoverflow.com/questions/25026399/uncaught-error-invariant-violation-findcomponentroot-110-unable-to) – Brigand Nov 01 '14 at 15:58

5 Answers5

34

You should read the full error message (at least that's what I am seeing):

Unable to find child 2 of element. This probably means the DOM was unexpectedly mutated (e.g., by the browser), usually due to forgetting a <tbody> when using tables, nesting tags like <form>, <p>, or <a>, or using non-SVG elements in an parent.

Every table needs a <tbody> element. If it doesn't exist, the browser will add it. However, React doesn't work if the DOM is manipulated from the outside.

Related: Removing row from table results in TypeError

Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 8
    Ah OK. When React first renders without a tbody, the browser then inserts it. On re-render there is a discrepancy between what React wants to render and what is in the DOM, hence the error. Thanks, day 2 using React here... – koosa Nov 01 '14 at 14:07
  • 1
    Yep, Chrome especially will close tags, remove p tags that are illegally nested in other p tags, all kinds of things that can really confuse you sometimes... – koosa Aug 21 '15 at 01:46
5

I encountered this when dealing with p tags. I had nested paragraphs within paragraphs.

To resolve the problem I replaced the wrapping p element with a div element.

Before:

render: function render() {
    return (
        <p>
            <p>1</p>
            <p>2</p>
        </p>
    );
}

After:

render: function render() {
    return (
        <div>
            <p>1</p>
            <p>2</p>
        </div>
    );
}
tukkaj
  • 596
  • 1
  • 6
  • 16
  • ah this looks like the issue I'm having.. but without seeing the surrounding code your example doesn't really make much sense. – krivar Jul 27 '15 at 14:00
  • Oh, sorry! Those tags should be output by a render function in a React component. @krivar, I updated my answer to be more accurate. – tukkaj Jul 31 '15 at 17:58
  • You can't have p tags within p tags because it's illegal. Browsers "fix" it for you – Zach Saucier Mar 25 '16 at 17:53
0

For people who are using react-templates:

You have to generate the <tbody> tag in the .jsx file. If you only add it in the .rt file you still get the error message.

this.tbody = <tbody>{tablerows}</tbody> // - in .jsx
zeillah
  • 76
  • 3
0

In My case the fix is to remove spaces in Table render from

<tbody> {rows} </tbody>

to

<tbody>{rows}</tbody>
yasarui
  • 6,209
  • 8
  • 41
  • 75
-1

I think your problem is with using the <th> tag in multiple rows. <th> is reserved for the header row. Try replacing it with <td> everywhere except in the first row. Also you should wrap the header in a <thead> tag and the rest in a <tbody> tag:

var header = [
  <tr onClick={this.handleCollapseClick}><th>Header 1</th><th>Header 2</th><th>Header 3</th></tr>
];

var body = [];
if(!this.state.collapsed){
  body.push(<tr><td>Row1 1</td><td>Row1 2</td><td>Row1 3</td></tr>);
}

body.push(<tr><td>Footer 1</td><td>Footer 2</td><td>Footer 3</td></tr>);

 return <div>
     <table>
         <thead>{header}</thead>
         <tbody>{body}</tbody>
     </table>
 </div>;
kraf
  • 1,269
  • 12
  • 21