Description
This has already been discussed before (#14740), but there wasn't a reproducing example for this kind of issue and I think that my use case is also a bit different.
Do you want to request a feature or report a bug?
I believe this can be considered a bug.
What is the current behavior?
In order to reproduce this issue using Chrome, you will need to install the following Chrome extension called TransOver:
https://chrome.google.com/webstore/detail/transover/aggiiclaiamajehmlfpkjmlbadmkledi?hl=en
I use it to translate text on hover.
The only thing that this extension does is appending a tooltip with the translated text to the body
HTML element when you hover an element with text (it doesn't seem it appends stuff below the React's root div
element).
I have created two code sandboxes to show you better and explain the problem.
It is a minimal example of a movie app like the one Dan showed at JSConf 2018 in Iceland, though not as beautiful as his and without all that cool Suspense stuff, but at least it uses hooks :) .
The two code sandboxes are essentially identical, the only difference is that the first one (heuristic-lake-exxvu
) uses a div
element for MovieApp
, whereas the second (magical-grass-016kc
) uses a React.Fragment
(<></>
) component:
heuristic-lake-exxvu
's MovieApp
:
const MovieApp = () => {
const [currentMovie, setCurrentMovie] = useState(initialCurrentMovieState);
const { isLoading, id: currentMovieId, movieDetails } = currentMovie;
...
return (
<div> // <======================= Uses a `div`
{isLoading ? (
"Loading..."
) : (
...
magical-grass-016kc
's MovieApp
:
const MovieApp = () => {
const [currentMovie, setCurrentMovie] = useState(initialCurrentMovieState);
const { isLoading, id: currentMovieId, movieDetails } = currentMovie;
...
return (
<> // <======================= Uses a fragment
{isLoading ? (
"Loading..."
) : (
...
Now, if you open heuristic-lake-exxvu
and click on the Show movie info
button of any movie in the list, you will see the Loading...
text before the promise with the data of the movie resolves, and the Movie
component is rendered.
Before the promise resolves, try hovering on the Loading...
text with the TransOver
extension enabled, you should see:
The world makes sense here, no errors, no warnings, everything works.
Now try to do the same thing on magical-grass-016kc
, as soon as you hover Loading...
, you will see the NotFoundError: Failed to execute 'removeChild' on 'Node'
error logged in the browser's console:
Here is a streamable video showing this same error:
What is the expected behavior?
In heuristic-lake-exxvu
(uses a div
instead of React fragment), everything worked.
The TransOver extension appends to body
and does not modify the React's root div
neither does it append stuff below it, so I would expect the code in the React fragment example (magical-grass-016kc
) to behave the same and work as in heuristic-lake-exxvu
.
Chrome is plenty of useful extensions like this one and they should not really interfere with React, I think that users using React applications may also install other extensions which modify the DOM which they find useful.
If an extension appends to body like TransOver does, I wouldn't expect React to have problems with it and cause undesirable effects and application errors like this one.
This is my opinion, I would be very glad to hear what you think about it, and if you think I have spotted a bug of React fragments (I think it's a bug because, again, it works when using a div
in heuristic-lake-exxvu
).
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
Browser: Chrome
React v16.11.0
React DOM v16.11.0