I'm building a Next.js 15 app with a CarrotSearch foamtree component.
Following the example here, I get this error.
Uncaught (in promise) FoamTree: visualization already embedded in the element.
I've tried to prevent recreating the treemap if it's already present on the DOM, but to no avail. Any ideas?
//@ts-ignore
const Treemap = ({ data }) => {
//@ts-ignore
const element = useRef()
const [ treemap, setTreemap ] = useState();
useEffect(() => {
import("@carrotsearch/foamtree").then(module => {
setTreemap(new module.FoamTree({
element: element.current,
//...
}));
});
return () => {
if (treemap) {
//@ts-ignore
treemap.dispose();
//@ts-ignore
setTreemap(null);
}
}
}, []);
useEffect(() => {
if (treemap) {
//@ts-ignore
treemap.set("dataObject", data);
}
}, [ treemap, data ]);
return (
//@ts-ignore
<div ref={element} className="absolute w-full h-full" id="treemap"></div>
);
};
export default Treemap;
The problem is a result of the incorrect implementation of the dynamic importing in the example. I've updated the example code to properly handle importing and disposal of FoamTree:
https://github.com/carrotsearch/nextjs-foamtree/blob/master/src/FoamTree.js
The original implementation had several problems:
treemap.dispose()
was never called.
The reason for this is that the disposal function returned from useEffect()
closed over the undefined
value of treemap
, so it never called treemap.dispose()
. The hook did not specify the treemap
dependency, so the hook did not re-run to update the treemap
to a non-undefined value once it was available. As a result, FoamTree was not getting disposed after the React component unmounting, which lead to the "already embedded" error on the subsequent mounting.
Race condition ignored.
The original implementation ignored a potential race condition where the component gets unmounted before the dynamic import finishes loading.
The updated implementation splits the initialization into three hooks:
The new implementation behaves correctly when unmounting / re-mounting the component. It also should not fail with React strict mode enabled.