Error from orphaned elements trying to render
See original GitHub issueI’m getting this error in a certain code path is my application:
The rerender() function was called on a node without a parent element.
I can’t manage to create a minimal reproduction for this, and I’ve spent a bunch of hours trying to figure out what’s going on here, even had a friend help debug the forgo source code tonight, but I haven’t figured it out. I’m hoping you have an idea.
It seems that when my component rerenders and returns null
, Forgo isn’t correctly updating its bookkeeping. It holds onto the old detached div
in args.element
, which eventually makes the rerender throw an error. The component’s unmount()
method isn’t called in this scenario, either.
The page visually renders fine, but I previously managed to get this error in an infinite loop that locked up page, and since I don’t understand what’s going wrong I can’t just let it go.
I have a parent and a child that both depend on the same forgo-state state, and am using forgo-router.
The application flow that’s happening looks like this: MyComponent
onclick
-> ajax -> update forgo-state -> MyComponent.render
-> queueMicrotask(navigateTo('/app'))
, return null
-> OtherComponent.render
-> ajax => update forgo-state -> MyComponent.render
MyComponent
shouldn’t get that second render, because the page has navigated away. It should be unmounted. But because it wasn’t, forgo-state tries to rerender MyComponent
, but because it’s holding onto the old div
(even though the last render returns null
) Forgo tries to rerender it and blows up.
(Why queueMicrotask
? because forgo-router errors out if the very first render the app does includes an inline navigateTo()
call because no components have corresponding DOM nodes yet).
If MyComponent
, instead of returning null
, returns something like <p>hello</p>
I don’t get the error. If I do the navigateTo()
immediately in the render rather than in queueMicrotask
, I don’t get the error.
I see the error printed several times, if that means anything.
Top of render()
in MyComponent
:
render() {
if (
authnstate.accessExpiresInHours === null ||
authnstate.accessExpiresInHours > 0
) {
queueMicrotask(() => navigateTo("/app"));
//return <p>Redirecting...</p>;
return null;
}
The component is declared with bindToStates([authnstate], ...)
.
MyComponent
lives under App
, which is also bound to the same state. App contains the router:
{...
matchExactUrl(myComponentUrl, () => <MyComponent />) ||
<p>Welcome!</p>}
Please let me know if I can provide any other info that’ll help. I’m sorry that I can’t trigger this in a minimal sandbox, only in my full application.
Issue Analytics
- State:
- Created 2 years ago
- Comments:16 (16 by maintainers)
Top GitHub Comments
That’s a very good point, I agree. Let’s make this change then.
Sure thing. If you wind up wanting to screen share, it looks like I’ve got Friday morning EST open.