-
Notifications
You must be signed in to change notification settings - Fork 47k
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
Make React resilient to DOM mutations from Google Translate #11538
Comments
Thanks for the report - I can also reproduce this bug. |
Could be related? #9836 |
We can also reproduce this bug on our own app. Thanks for the report. Edit: About the next comment: we also ended up applying this “fix”. It obviously hurts accessibility and users are still triggering this error by right clicking “Translate to X” on Chrome as this meta tag only removes the top-bar translation suggestion. |
I "fixed" my app for users running into this by disabling Chrome's translation using this method (until the underlying issue is fixed): https://stackoverflow.com/a/12238414/684353 Edit 2024: Skip to my write-up that covers the entire issue and all of the listed fixes: #11538 (comment) (the one in the OP is broken) |
This error also occurs if you use https://localizejs.com for translation. I'm assuming since they manipulate the DOM and React can't reconcile the changes. This took forever to track down and I'm putting it here in case anyone else is trying use localizejs and React16. The issue is with localizejs. The workaround is to add import { render } from 'react-dom'
const appRoot = document.getElementById('app')
appRoot.setAttribute('notranslate', true)
render(<App />, appRoot) UPDATE In the meantime this is the solution we are using: Usagetranslate string |
@gaearon can you provide any guidance about if and when React could be patched to be resilient against this sort of bug? |
4 of 7 customers had this problem with react, but it's not happen in all computers, chrome last version 63 working ok for some users but not in others, so it's produces by: no use some keys in react elements, google translate plugins and anothers plugins.. the only solutions is to tell people turn of his plugins... |
I've just run into this issue as well, which was really hard to figure out. The only clue was that all the strings in Sentry reports were non-English. How is this not causing problems across all major websites using React 16? Any extension modifying the DOM (which there are a lot, translators, password managers, etc.) can totally break a React website. The only workaround I found right now is to:
As recommended above. |
Is there any workaround for this? How is it solved on facebook.com, where Chrome translate works with React 16? |
it's ok: |
If you want to help fix this, please create a small reproducing case that doesn't involve extensions, but manually reproduces what they might do to the DOM. Then we can take a look. |
@gaearon: @fritz-c 's original snippet doesn't involve extensions: Full page here: |
It involves using Google Translate. I'm asking to create a reproduction case that does what Google Translate would do, but with DOM API calls. So that we can see what exactly is causing the issue. |
I don't think anyone can answer that, except Google Chrome team. I'm not even sure if Translate is part of the open source Chromium project. |
I don't think you need to know the internals of what Google Translate is doing. Look at DOM before and after for a single word, set some DOM breakpoints, and that should tell you the manipulations necessary to reproduce it. A mutation observer can help too. |
OK, just simply looking at the DOM it's obvious that it gets changed significantly:
It's interesting that this works well in React 15. |
Right, so I encourage you to write a minimal case in CodeSandbox that does similar mutations and try to reproduce the problem 🙂 |
I did the mutation observers, but haven't been able to replicate it in a way which wouldn't break React 15 as well. I pass it on to a more experienced person from here: |
I used Chrome DOM breakpoints to see what Google Translate was doing under the hood, and created a minimal reproduction that closely emulates how it replaces text. Now with cross-browser compatibility, it breaks in Safari, Firefox and Chrome. The key lines are at the bottom: // Get the text node "checked"
const myEl = document.querySelector("div > div > div").childNodes[0];
// Create an arbitrary font element to replace it with
const fontEl = document.createElement("font");
myEl.parentElement.insertBefore(fontEl, myEl);
myEl.parentElement.removeChild(myEl); This puts the DOM node in a state that will cause the next update by React to throw an error. I ran the same mutation code in the demo for React 15 (changing |
Thanks! Any idea why it inserts |
I have no idea. If I had to venture a guess, I'd say it's related to how they incrementally translate large blocks of text (only what's on the screen), and inconsistency between browsers in how bare text nodes are handled. |
Adding a bit more of information. The examples below are based on the ones by @hyperknot and @fritz-c. The problem is that Google Translate replaces text nodes with React throws in the following cases:
// Case 1
<div>
{condition && 'Welcome'}
<span>Something</span>
</div>
// Doesn't throw
<div>
{condition && 'Welcome'}
</div>
// Case 2
<div>
{condition && <span>Something</span>}
Welcome
</div> WorkaroundWe can avoid these errors by invalidating the conditions above. The easiest workaround is to wrap those text nodes with // A workaround for case 1
<div>
{condition && <span>Welcome</span>}
<span>Something</span>
</div>
// A workaround for case 2
<div>
{condition && <span>Something</span>}
<span>Welcome</span>
</div> |
Just curious, has anyone found an existing eslint rule that warns or errors on this? Our Sentry logs have been filled with these errors for a few months now, so it's great to identify the issue. Not sure we'll be able to have our team "remember" to do this convention, though, but it seems lintable. |
What is React’s common behaviour for dealing with modified DOM trees? I assume it is to override the changes and regain certainty about the DOM’s state. Would it be ok to fully invalidate and rerender the
|
@shuhei Thanks for great analysis. |
I had the same issue and this wasn't google translate specific. The error occurs because react still has state of the element being removed and can't find it in the component. This can be caused by arbitrarily removing an element being conditionally rendered by react. Take for example:
Now if probably based on an event in the childValue or on the parent value, you then do something like:
That error would occur because, the state of the childValue still exist and its a derivedElement based off that conditional. So instead of having to remove it arbitrarily, you specifically need to deal with it through the childValue by setting childValue to null or whatever way fits your usecase |
- Fix JavaScript errors occurring when Chrome's translation feature is enabled - Resolve conflicts between elements inserted by the translation feature and application's DOM manipulation References: - facebook/react#11538 (comment) Related Issue: aws-samples#518
- Fix JavaScript errors occurring when Chrome's translation feature is enabled - Resolve conflicts between elements inserted by the translation feature and application's DOM manipulation References: - facebook/react#11538 (comment) Related Issue: aws-samples#518
For my project, translation is a must. Because it is something that has to be done. So let's think about this problem from another angle. |
I think it still relates to the previous thing I talked about, is there no way for you to move the implementation into a conditional instead that. So for example, instead of using a removeChild, you would set a ref to false or something or a use State of your implementation allows and that change in state is what would remove the child. When you move the logic into a conditional instead of interacting with the actual Dom element, it should fix the issue. Or this still can't work for your use case? |
For anyone still having problems with this in 2024, we created an ESLint rule for helping address the issue. It is important to note that this is by no means a perfect solution. We are aiming to find the best middle ground between reporting as many problematic patterns as possible, but not returning too many false positives. Our general approach is to identify conditionally rendered text nodes with siblings. There are, however, known limitations to the rule which we have outlined in the readme. It’s worth also noting that this list is not exhaustive. Hopefully it can help others the way we have benefitted. For context, we are a German company with customers who speak many different languages, so it was understandably important to identify as many potentially problematic React patterns as possible. |
I've noticed that while tracking down some of these, I've been able to find the exact nodes causing the problem by enabling 'Pause on caught exceptions' in Chrome, and then stepping through until it hits the removeChild error. But that's the only way.. It seems once the error shows on the actual browser page, there's no way to look at the exception information. Is there a better way to quickly get to the actual exception without having to step through every exception? |
I think the easiest way is to wrap your element with a div tag and add transate="no" if it is not need to be translated. |
çok teşekkürler |
Coming from search? See workaround here: #11538 (comment). And star this issue: https://bugs.chromium.org/p/chromium/issues/detail?id=872770.
Do you want to request a feature or report a bug?
Bug, though there's a decent chance it's a Chrome/Google Translate one
What is the current behavior?
When using Google Translate on a page using React 16, a certain code pattern produces a Javascript error (
Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
) when the rendered content changes.If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://jsfiddle.net or similar (template for React 16: https://jsfiddle.net/Luktwrdm/, template for React 15: https://jsfiddle.net/hmbg7e9w/).
(This has only been checked on macOS 10.13.1)
The source of the example can be found at https://codesandbox.io/s/qq49kwjynj
The part of the code that seems to cause it is the following two lines:
Changing this to the following fixes the behavior with Google Translate:
What is the expected behavior?
It should not produce an error.
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
I created an identical example with React 15 at the following pages:
https://p93xxmr0rq.codesandbox.io/
https://codesandbox.io/s/p93xxmr0rq
When repeating the same steps outlined above, no error was produced.
It only seems to affect React 16.
As this is a Chrome-only feature, it only affects Chrome.
The text was updated successfully, but these errors were encountered: