Hi,
I am implementing a custom widget in Typescript+React that has its own UI, but when I try to display the widget in an expand widget, I just get [Object Object] when the Expand widget expands to display my widget.
function App() {
const [viewState, setViewState] = useState(null);
const mapDiv = useRef(null);
const webMap = useRef(null);
const mapView = useRef(null);
const printWidget = useRef(null);
const printExpand = useRef(null);
const config = useRef({
printServiceVersion: 10.6,
filename: "Print",
widgetMode: true,
});
useEffect(() => {
if (mapDiv.current) {
esriConfig.portalUrl = portalURL;
webMap.current = new WebMap({
portalItem: {
id: "7a7350f559734d9197dca846de069342",
},
});
mapView.current = new MapView({
container: mapDiv.current,
map: webMap.current
});
printWidget.current = new PatrickPrint({ map: webMap.current, view: mapView.current, config: config.current });
printExpand.current = new Expand({
expandIconClass: "esri-widget--button esri-widget print-icon",
expandTooltip: "Print",
view: mapView.current,
content: printWidget.current,
expanded: false
});
mapView.current.ui.add(printExpand.current, "top-right");
webMap.current.when(() => {
setViewState({ view: mapView.current })
})
}
}, [mapDiv]);
return (
<div className="App" ref={mapDiv}></div>
);
}
export default App;
In my widget, I have stripped it down to the bare code from the /jsapi-custom-ui example project:
export default class PatrickPrint extends React.Component<PatrickPrintParams, State> {
render() {
return (<div>Hello</div>);
}
}
When it loads, I get this:
When I'm expecting a simple div with 'Hello' to be rendered.
Solved! Go to Solution.
The Expand widget can't display React vdom directly. You'll probably want to look at portals for React.
https://react.dev/reference/react-dom/createPortal
You can place a dom element in the expand widget that is used as the element a React component is displayed.
Here is a blog post showing how it would work for Popup, similar to how it would work in Expand.
The Expand widget can't display React vdom directly. You'll probably want to look at portals for React.
https://react.dev/reference/react-dom/createPortal
You can place a dom element in the expand widget that is used as the element a React component is displayed.
Here is a blog post showing how it would work for Popup, similar to how it would work in Expand.
Hi @NikMartin this isn't an issue with the ArcGIS JS SDK. It's a problem with the React component coding, it looks like the component (as an HTMLElement) has not been imported into the app correctly. Here is a conceptual example: https://developers.arcgis.com/javascript/latest/custom-ui/#import-the-component-into-your-applicatio.... Without a reproducible sample via a github repo or Stackblitz we can't tell for certain. You'll need to provide a link to one if you are still stuck.
Also note, React recommends not using Class components: https://react.dev/reference/react/Component. They recommend migrating to functions, which is the pattern we demonstrate in the jsapi-custom-ui sample.
Thank you Andy, I was able to get it working with a few more Google searches, by injected a div into the DOM, like:
function App() {
const targetContainer = document.createElement('div');
const root = createRoot(targetContainer);
const [viewState, setViewState] = useState(null);
const mapDiv = useRef(null);
const webMap = useRef(null);
const mapView = useRef(null);
const printExpand = useRef(null);
useEffect(() => {
if (mapDiv.current) {
webMap.current = new WebMap({
portalItem: {
id: "7a7350f559734d9197dca846de069342",
},
});
mapView.current = new MapView({
container: mapDiv.current,
map: webMap.current
});
printExpand.current = new Expand({
expandIconClass: "esri-widget--button esri-widget print-icon",
expandTooltip: "Print",
view: mapView.current,
content: targetContainer,
expanded: false
});
mapView.current.ui.add(printExpand.current, "top-right");
webMap.current.when(() => {
setViewState({ view: mapView.current })
})
root.render(
<PatrickPrint map={webMap.current} view={mapView.current} config={config.current}/>
);
}
}, [mapDiv]);
return (
<div className="App" ref={mapDiv}></div>
);
}
Not as elegant as I hoped, but seems to be working fine.