Displaying React based widget from Expand Widget

850
3
Jump to solution
08-01-2023 12:48 PM
NikMartin
New Contributor II

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:

Screenshot 2023-08-01 144613.png

 

 

When I'm expecting a simple div with 'Hello' to be rendered.

Tags (3)
0 Kudos
1 Solution

Accepted Solutions
ReneRubalcava
Frequent Contributor

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.

https://odoe.net/blog/popup-react-portals

View solution in original post

0 Kudos
3 Replies
ReneRubalcava
Frequent Contributor

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.

https://odoe.net/blog/popup-react-portals

0 Kudos
AndyGup
Esri Regular Contributor

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.

0 Kudos
NikMartin
New Contributor II

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.

0 Kudos