-
Notifications
You must be signed in to change notification settings - Fork 32
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
Unhandled Rejection (NotFoundError): Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node. #22
Comments
Hmm, I see, thanks for reporting this. In general that shouldn't happen, and that doesn't happen in the examples here, so there's something unusual in your use case that we haven't been testing. I'm not sure how to reproduce this from your description though, unfortunately. Can you provide a small example of the issue, e.g. by editing the examples in this repo (https://github.com/httptoolkit/react-reverse-portal/blob/master/stories/html.stories.js) or using codesandbox.io or similar? If that's not practical, if you could share the relevant code from your application then that might help shine a light on the issue. |
Going to close this for now, but I'm happy to look into it further later if you can provide some more info. |
Reproduction https://codesandbox.io/s/misty-cookies-jztzjq?file=/src/App.js import { useState } from "react";
import { createHtmlPortalNode, InPortal, OutPortal } from "react-reverse-portal";
export default function App() {
const portalNode = createHtmlPortalNode();
const [crash, setCrash] = useState(false);
return (
<div className="App">
<button onClick={() => setCrash(true)}>Click here to crash!</button>
<InPortal node={portalNode}>Portal contents</InPortal>
{crash && <div />}
<OutPortal node={portalNode} />
</div>
);
} Cause
Solution? One thing that might work, is to render an empty text node directly before the This "fix" is as simple as this: import { useState } from "react";
import {
createHtmlPortalNode,
InPortal,
OutPortal
} from "react-reverse-portal";
export default function App() {
const portalNode = createHtmlPortalNode();
const [crash, setCrash] = useState(false);
return (
<div className="App">
<button onClick={() => setCrash(true)}>Click here to crash!</button>
<InPortal node={portalNode}>Portal contents</InPortal>
{crash && <div />}
{"" /* <- I only added this empty text node */}
<OutPortal node={portalNode} />
</div>
);
} |
Hi @brenthmiras, thanks for reporting this! That makes sense, although I haven't run into it myself anywhere before, really interesting find. I think your suggested solution makes perfect sense, that's a great idea. Would you be open to opening a PR to make OutPortals add this extra empty text node automatically? |
Another workaround is to simply wrap the OutPortal in a div: <div>
<OutPortal node={node} />
</div> This is less likely to affect the DOM or the styling. |
That would work, and it's a nice quick workaround you can use to fix this today. It does affect the DOM structure though in a way that could affect styles (e.g. direct descendent selectors) which I'd like to avoid. Using an empty text node doesn't have that problem, and should work equally well as a proper fix, so while an extra div is good as a quick workaround, I'd like to avoid implementing that as the real solution. |
Disclaimer: I'm not actually using react-reverse-portal. But I am doing something similar to it for a project at work, so I figured I'd share my findings at the time in my previous comment.
This is exactly the problem I ran into, I have some existing styles using direct descendent and sibling selectors, which would both break by adding a wrapping The problem described in this issue—where React tries to insert a new element before the detached placeholder node—can be fixed by rendering the empty text node before the "out portal". However, I also ran into another problem which was not fixed by the empty text node and forced me to add wrapping That problem occurs when the order of two "out portals" (including empty text nodes) is changed. Here, React doesn't know that the "placeholder" node was swapped for the "replaced" node. So when the order of the "out portals" changes, React just moves the empty text node and placeholder node in the DOM to the new location, leaving the replaced node behind. Consider this example (not real code):
Then this is what happens in the DOM after the order of these components in swapped:
At this point I gave up on trying to keep away from wrapping elements, because it felt like any fix would rely too much on React internals and could break at any moment or in weird edge cases. I haven't tried reproducing this other problem with react-reverse-portal, but I expect the same problem will probably occur here. One of the examples does something similar to this (this example), but there the actual |
Oooh, that's really interesting, and yes that's a complicated case that's not handled well right now. Any idea what the actual DOM transformations React is doing there are? The In the meantime, you can probably handle this (and many other similar cases) by using |
It does work!! Thanks |
I have a component
<ComponentWithVideo />
that contains a list of tracks that are being rendered in a single<video/>
element.That I rendered with
<InPortal />
and displayed to<OutPortal />
This error occurs when I add another track and
<ComponentWithVideo(s) />
re-renders.The text was updated successfully, but these errors were encountered: