mirror of
https://github.com/penpot/penpot.git
synced 2026-03-17 16:06:24 +00:00
🐛 Fix removeChild crash on portal-on-document* unmount
The previous implementation passed document.body directly as the React portal containerInfo. During unmount, React's commit phase (commitUnmountFiberChildrenRecursively, case 4) sets the current container to containerInfo and then calls container.removeChild() for every DOM node inside the portal tree. When two concurrent state updates are processed — e.g. navigating away from a dashboard section while a file-menu portal is open — React could attempt document.body.removeChild(node) twice for the same node, the second time throwing: NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node. The fix allocates a dedicated <div> container per portal instance via mf/use-memo. The container is appended to body on mount and removed in the effect cleanup. React then owns an exclusive containerInfo and its unmount path never races with another portal or the modal container (which also targets document.body). Signed-off-by: Andrey Antukh <niwi@niwi.nz>
This commit is contained in:
@@ -11,6 +11,11 @@
|
||||
|
||||
(mf/defc portal-on-document*
|
||||
[{:keys [children]}]
|
||||
(mf/portal
|
||||
(mf/html [:* children])
|
||||
(dom/get-body)))
|
||||
(let [container (mf/use-memo #(dom/create-element "div"))]
|
||||
(mf/with-effect []
|
||||
(let [body (dom/get-body)]
|
||||
(dom/append-child! body container)
|
||||
#(dom/remove-child! body container)))
|
||||
(mf/portal
|
||||
(mf/html [:* children])
|
||||
container)))
|
||||
|
||||
Reference in New Issue
Block a user