Hello everyone,
I am working with ArcGIS API for JavaScript 4.34 in a React + Vite (TypeScript) project.
I was able without any issue to:
In order to better manage screen space, I then tried to place the Sketch widget inside an Expand widget.
This is where the difficulties started.
Issue encountered
Most of the time, the Expand appears empty
After several attempts, I managed to make the Sketch widget appear inside the Expand
However, this then leads to DOM-related errors on the React side, such as:
Uncaught 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.
or:
Uncaught DOMException: Node.insertBefore: Child to insert before is not a child of this node
React 32
performWorkUntilDeadline scheduler.development.js:45
react-dom_client.js:9714:50
These errors usually occur:
after a React re-render,
or during the mount / unmount lifecycle of the Sketch widget,
even though the widget initially appears to work correctly inside the Expand.
Technical context
It seems I am facing a conflict between ArcGIS’ imperative DOM management and React’s virtual DOM, especially when the widget is hosted inside an Expand.
Question
Is there:
an officially recommended Esri pattern to properly integrate the Sketch widget inside an Expand in a React environment?
a known limitation or documented constraint regarding Expand + React?
a best practice to avoid these insertBefore errors in this specific scenario?
Here is the relevant code:
// Widget Sketch
useEffect(() => {
const view = viewRef.current;
const panel = stylerPanelRef.current;
const layer = sketchLayerRef.current;
if (!view || !panel || !layer) return;
// créer le container Sketch
const sketchContainer = document.createElement("div");
sketchContainer.className =
"w-full h-auto border border-slate-300 dark:border-slate-700 rounded-md mb-2";
// point d’ancrage STABLE géré par React (le bouton)
const clearButton = panel.querySelector("button");
if (clearButton && clearButton.parentNode === panel) {
// solution StackOverflow : insertBefore(parent, nextSibling)
panel.insertBefore(sketchContainer, clearButton);
} else {
// fallback ultra-sécurisé
panel.appendChild(sketchContainer);
}
// init Sketch
const sketch = new Sketch({
view,
layer,
container: sketchContainer,
creationMode: "single",
visibleElements: {
createTools: {
point: false,
polyline: true,
polygon: true,
rectangle: true,
circle: true,
},
selectionTools: {
"lasso-selection": true,
"rectangle-selection": true,
},
settingsMenu: true,
},
});
const createHandle = sketch.on("create", (event) => {
if (event.state === "complete" && event.graphic?.geometry) {
selectBySketchGeometry(event.graphic.geometry);
}
});
sketchWidgetRef.current = sketch;
return () => {
createHandle.remove();
sketch.destroy();
sketchWidgetRef.current = null;
// nettoyage DOM sécurisé
if (panel.contains(sketchContainer)) {
panel.removeChild(sketchContainer);
}
};
}, [selectBySketchGeometry]);JSX:
{/* Styler Panel (utilisé par le widget Expand ArcGIS) */}
<div ref={stylerPanelRef} className="p-3 space-y-2 text-sm bg-white dark:bg-slate-800 h-auto">
<h3 className="font-bold text-slate-700 dark:text-slate-200">Sketch Styler</h3>
{/* Le conteneur Sketch est ajouté dynamiquement via JavaScript */}
<button
type="button"
className="px-3 py-1.5 text-sm font-medium text-white transition-colors bg-blue-600 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-slate-800"
onClick={() => sketchLayerRef.current?.removeAll()}
>
Clear Sketches
</button>
</div>Thank you in advance for your help and feedback.