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

React will not render tbody components. Returns "Uncaught Error: Invariant Violation: findComponentRoot(..., .0): Unable to find element. This probably means the DOM was unexpectedly mutated..." #3762

Closed
davecorning opened this issue Apr 28, 2015 · 19 comments

Comments

@davecorning
Copy link

Problem:
(fiddle here: http://jsfiddle.net/davecorning/4wq4ycbn/2/)

I am attempting to dynamically update an existing html table with Ajax data.

I have 3 components: a Tbody component which renders a collection of DataRows (representing a collection of <tr> elements), each of which renders a collection of Cells (representing all the <td> elements in a row).

I understand that if there is an html table without a tbody element, browsers will insert one and cause problems, but that's not what's happening here. I have an html table with a tbody that I wish to replace.

I get the following error when I run the code:

Uncaught Error: Invariant Violation: findComponentRoot(..., .0): Unable to find 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 <svg> parent. Try inspecting the child nodes of the element with React ID ``.

The code succeeds if I simply change it to render a table (on top of a table element, of course).

I am running both Firefox 37.0.1 (linux) and Chrome 42.0.2311.90 + the ReactJS extension (in linux)

Any help would be appreciated.

Thanks,

-dave

@StoneCypher
Copy link

[19:32:44] <StoneCypher> mutexjp: if you started with an empty table then added those, 
then there's already been one added by the browser, is why

[19:33:00] <StoneCypher> mutexjp: the browser will add one *immediately*

@davecorning
Copy link
Author

That's not the case. Like I mentioned in IRC, i'm starting with an existing table with an empty tbody, like this:

<table>
<thead><tr><th>col 1</th><th>col 2</th></thead>
<tbody id='replace_me'></tbody>
</table>

@waldreiter
Copy link
Contributor

<tbody id='replace_me'></tbody>

Render will not replace the <tbody>, but will replace its children. So by rendering a <tbody> you end up with 2 <tbody>s.

@davecorning
Copy link
Author

The React.render documentation (https://facebook.github.io/react/docs/top-level-api.html#react.render) states that the contents of the container node (in this case, <tbody>) gets replaced:

Note:
React.render() replaces the contents of the container node you pass in. In the future, it may be
possible to insert a component to an existing DOM node without overwriting the existing children.

Is that somehow not the case for a <tbody> element?

@waldreiter
Copy link
Contributor

The docs are correct. The "container node" is in your case the <tbody> that is in the html. React does not remove it, but it changes its "contents". The contents is in your case another <tbody>, so you end up with 2 <tbody>s.

@sophiebits
Copy link
Collaborator

Yeah, unfortunately there's no way for you to manage only the tbody in React for the reasons already mentioned.

@StoneCypher
Copy link

(two tbodies is actually completely valid, i'll point out, more to be a troll than anything, though it is true)

@sophiebits
Copy link
Collaborator

@StoneCypher That's true but it doesn't help here.

@davecorning
Copy link
Author

@cody @spicyj Thank you very much for your responses. I guess part of the problem was my misinterpretation of the docs. I indeed thought that the container node would be replaced.

Either way, now that I know i cannot manage only the tbody in React, I'll take a different approach. Thanks again!

@scarletsky
Copy link

@spicyj
I have the same issue. I've checked my table, I do have a tbody tag.
When I add tr dynamically, it works as expected without error.
But when I remove tr dynamically, it works, the view remove tr as expected, but it also throw error:

Uncaught Error: Invariant Violation: findComponentRoot(..., .0.1.0.0:$0.0:$0.0.$4): Unable to find 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 <svg> parent. Try inspecting the child nodes of the element with React ID ``.

I have no idea how to solve it.

@sophiebits
Copy link
Collaborator

@scarletsky If you can post a simple jsbin that shows the problem (in a new GitHub issue, ideally), I'll be happy to take a look.

@scarletsky
Copy link

@spicyj
Here is a demo: http://codepen.io/scarletsky/pen/gPwvBQ

After two days debugging, I can sure that the error is related to 73L-78L.
But I still do not know why this happen.

@sophiebits
Copy link
Collaborator

Thanks for the solid test case.

I have not confirmed, but I believe this is also a manifestation of #2410. I believe it would be fixed if you instead added and removed rows in the stores in response to CHANGE_TABLE_ROWS directly (and drop ADD_ROW and REMOVE_ROW completely) instead of chaining actions together in componentWillReceiveProps. What you're doing here is generally considered a Flux antipattern and also ties your code to your views more, which makes it harder to refactor your code later. I'll leave this open until I can confirm that this is in fact a dupe of #2410.

@sophiebits sophiebits reopened this Dec 28, 2015
@sophiebits
Copy link
Collaborator

Yeah, I'm 95% sure this is #2410.

@scarletsky
Copy link

Not sure whether it is related to #2410.

But I know that if Table component get rowIds from Container component via props, every thing works as expected.

However, if Table component get rowIds from store via ReactRedux.connect, it will throw Invariant Violation error.

@scarletsky
Copy link

@spicyj

In fact, I am implementing a spreadsheet like excel with react.
Here is my redux store:

{
  table: {
    id: 1
    rows: 2,
    cols: 3,
    rowIds: ['1-1', '1-2'] 
  },
  rows: {
    '1-1': {
      id: '1-1',
      cellIds: ['1-1-1', '1-1-2', '1-1-3']
    },
    '1-2': {
      id: '1-2',
      cellIds: ['1-2-1', '1-2-2', '1-2-3']
    }
  },
  cells: {
    '1-1-1': { ... },
    '1-1-2': { ... },
    ...
  }
}

As you see, when I change table's rows, I will dispatch CHANGE_TABLE_ROWS, and then caculate which action(ADD_ROW or REMOVE_ROW) should be dispatched in Table component. And then render Row component. In Row's componentDidMount function, I will also dispatch ADD_CELL action, and dispatch REMOVE_CELL action in componentWillUnmount functiion. (This part is not in the demo)

You say What I do above is antipattern. Should my store.table, store.rows, store.cells listen to CHANGE_TABLE_ROWS action to change themselves ?

@sophiebits
Copy link
Collaborator

@scarletsky I am not a flux expert, sorry – but my understanding is that chaining actions is always discouraged.

@gaearon
Copy link
Collaborator

gaearon commented Dec 30, 2015

Should my store.table, store.rows, store.cells listen to CHANGE_TABLE_ROWS action to change themselves ?

That's how Redux apps should work, yes.

@scarletsky
Copy link

@gaearon thanks for the information.

sophiebits added a commit to sophiebits/react that referenced this issue Apr 29, 2016
Fixes facebook#2410. Fixes facebook#6371. Fixes facebook#6538.

I also manually tested the codepen in facebook#3762 and verified it now works.
sophiebits added a commit to sophiebits/react that referenced this issue Apr 29, 2016
Fixes facebook#2410. Fixes facebook#6371. Fixes facebook#6538.

I also manually tested the codepen in facebook#3762 and verified it now works.
sophiebits added a commit that referenced this issue Apr 29, 2016
Fixes #2410. Fixes #6371. Fixes #6538.

I also manually tested the codepen in #3762 and verified it now works.
zpao pushed a commit that referenced this issue May 10, 2016
Fixes #2410. Fixes #6371. Fixes #6538.

I also manually tested the codepen in #3762 and verified it now works.
(cherry picked from commit c1e3f7e)
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

6 participants