Gojs with React functional Component

I need make a stateless functional component in react and I want to use ReactDiagram component .the below code was i got as an minimal example . I got some hooks issue while implementing in react. please mention if there was any example of functional component and stateless.

import React from 'react';

import * as go from 'gojs';

import './App.css';  


function App() {
  var $ = go.GraphObject.make;  // for conciseness in defining templates

  var myDiagram = $(go.Diagram, "myDiagramDiv",  // create a Diagram for the DIV HTML element
    {
      "undoManager.isEnabled": true  // enable undo & redo
    });

  // define a simple Node template
  myDiagram.nodeTemplate =
    $(go.Node, "Auto",  // the Shape will go around the TextBlock
      $(go.Shape, "RoundedRectangle", { strokeWidth: 0, fill: "white" },
        // Shape.fill is bound to Node.data.color
        new go.Binding("fill", "color")),
      $(go.TextBlock,
        { margin: 8, font: "bold 14px sans-serif", stroke: '#333' }, // Specify a margin to add some room around the text
        // TextBlock.text is bound to Node.data.key
        new go.Binding("text", "key"))
    );

  // but use the default Link template, by not setting Diagram.linkTemplate

  // create the model data that will be represented by Nodes and Links
  myDiagram.model = new go.GraphLinksModel(
    [
      { key: "Alpha", color: "lightblue" },
      { key: "Beta", color: "orange" },
      { key: "Gamma", color: "lightgreen" },
      { key: "Delta", color: "pink" }
    ],
    [
      { from: "Alpha", to: "Beta" },
      { from: "Alpha", to: "Gamma" },
      { from: "Beta", to: "Beta" },
      { from: "Gamma", to: "Delta" },
      { from: "Delta", to: "Alpha" }
    ]);
  return (
    <div id='myDiagramDiv' style={{width:'600px',height:'600px',border:'1px solid black'}}/>
  );
}
 export default App;

If you want to use https://github.com/NorthwoodsSoftware/gojs-react I suggest you look at https://github.com/NorthwoodsSoftware/gojs-react-basic.

Please read https://gojs.net/latest/intro/react.html

these are the statefull react app,but I need stateless , I’m facing errors on hooks

There are many possible interpretations of whether a component is “stateful” or “stateless”.

You can certainly make a GoJS Diagram read-only, to varying degrees: https://gojs.net/latest/intro/permissions.html

However you presumably do want your diagram to show the data that comes in via props, and to update when the props have changed. The problem is that there is potentially a lot of overhead in creating, initializing, and rendering a diagram, so one really would prefer not to re-create the diagram each time. That’s why the gojs-react ReactDiagram component is implemented the way that it is.

this thing is not about the permission or some else,
wheter react hooks can be used in gojs?, if yes how we could proceed
and need to do without the <ReactDiagram/> component, if it can be done by Diagram API ,how do I merge with stateless functional component

public handleDiagramEvent(e: go.DiagramEvent) {
    const name = e.name;
    switch (name) {
      case 'ChangedSelection': {
        const sel = e.subject.first();
        this.setState(
          produce((draft: AppState) => {
            if (sel) {
              if (sel instanceof go.Node) {
                const idx = this.mapNodeKeyIdx.get(sel.key);
                if (idx !== undefined && idx >= 0) {
                  const nd = draft.nodeDataArray[idx];
                  draft.selectedData = nd;
                }
              } else if (sel instanceof go.Link) {
                const idx = this.mapLinkKeyIdx.get(sel.key);
                if (idx !== undefined && idx >= 0) {
                  const ld = draft.linkDataArray[idx];
                  draft.selectedData = ld;
                }
              }
            } else {
              draft.selectedData = null;
            }
          })
        );
        break;
      }
      default: break;
    }
  }

  /**
   * Handle GoJS model changes, which output an object of data changes via Model.toIncrementalData.
   * This method iterates over those changes and updates state to keep in sync with the GoJS model.
   * @param obj a JSON-formatted string
   */
  public handleModelChange(obj: go.IncrementalData) {
    const insertedNodeKeys = obj.insertedNodeKeys;
    const modifiedNodeData = obj.modifiedNodeData;
    const removedNodeKeys = obj.removedNodeKeys;
    const insertedLinkKeys = obj.insertedLinkKeys;
    const modifiedLinkData = obj.modifiedLinkData;
    const removedLinkKeys = obj.removedLinkKeys;
    const modifiedModelData = obj.modelData;

    // maintain maps of modified data so insertions don't need slow lookups
    const modifiedNodeMap = new Map<go.Key, go.ObjectData>();
    const modifiedLinkMap = new Map<go.Key, go.ObjectData>();
    this.setState(
      produce((draft: AppState) => {
        let narr = draft.nodeDataArray;
        if (modifiedNodeData) {
          modifiedNodeData.forEach((nd: go.ObjectData) => {
            modifiedNodeMap.set(nd.key, nd);
            const idx = this.mapNodeKeyIdx.get(nd.key);
            if (idx !== undefined && idx >= 0) {
              narr[idx] = nd;
              if (draft.selectedData && draft.selectedData.key === nd.key) {
                draft.selectedData = nd;
              }
            }
          });
        }
        if (insertedNodeKeys) {
          insertedNodeKeys.forEach((key: go.Key) => {
            const nd = modifiedNodeMap.get(key);
            const idx = this.mapNodeKeyIdx.get(key);
            if (nd && idx === undefined) {  // nodes won't be added if they already exist
              this.mapNodeKeyIdx.set(nd.key, narr.length);
              narr.push(nd);
            }
          });
        }
        if (removedNodeKeys) {
          narr = narr.filter((nd: go.ObjectData) => {
            if (removedNodeKeys.includes(nd.key)) {
              return false;
            }
            return true;
          });
          draft.nodeDataArray = narr;
          this.refreshNodeIndex(narr);
        }

        let larr = draft.linkDataArray;
        if (modifiedLinkData) {
          modifiedLinkData.forEach((ld: go.ObjectData) => {
            modifiedLinkMap.set(ld.key, ld);
            const idx = this.mapLinkKeyIdx.get(ld.key);
            if (idx !== undefined && idx >= 0) {
              larr[idx] = ld;
              if (draft.selectedData && draft.selectedData.key === ld.key) {
                draft.selectedData = ld;
              }
            }
          });
        }
        if (insertedLinkKeys) {
          insertedLinkKeys.forEach((key: go.Key) => {
            const ld = modifiedLinkMap.get(key);
            const idx = this.mapLinkKeyIdx.get(key);
            if (ld && idx === undefined) {  // links won't be added if they already exist
              this.mapLinkKeyIdx.set(ld.key, larr.length);
              larr.push(ld);
            }
          });
        }
        if (removedLinkKeys) {
          larr = larr.filter((ld: go.ObjectData) => {
            if (removedLinkKeys.includes(ld.key)) {
              return false;
            }
            return true;
          });
          draft.linkDataArray = larr;
          this.refreshLinkIndex(larr);
        }
        // handle model data changes, for now just replacing with the supplied object
        if (modifiedModelData) {
          draft.modelData = modifiedModelData;
        }
        draft.skipsDiagramUpdate = true;  // the GoJS model already knows about these updates
      })
    );
  }

  /**
   * Handle inspector changes, and on input field blurs, update node/link data state.
   * @param path the path to the property being modified
   * @param value the new value of that property
   * @param isBlur whether the input event was a blur, indicating the edit is complete
   */
  public handleInputChange(path: string, value: string, isBlur: boolean) {
    this.setState(
      produce((draft: AppState) => {
        const data = draft.selectedData as go.ObjectData;  // only reached if selectedData isn't null
        data[path] = value;
        if (isBlur) {
          const key = data.key;
          if (key < 0) {  // negative keys are links
            const idx = this.mapLinkKeyIdx.get(key);
            if (idx !== undefined && idx >= 0) {
              draft.linkDataArray[idx] = data;
              draft.skipsDiagramUpdate = false;
            }
          } else {
            const idx = this.mapNodeKeyIdx.get(key);
            if (idx !== undefined && idx >= 0) {
              draft.nodeDataArray[idx] = data;
              draft.skipsDiagramUpdate = false;
            }
          }
        }
      })
    );
  }

you can see here the setState method, I need to do with React hooks

I’m not sufficiently familiar with React Hooks to be able to advise you as to what you could do.

nearly I did something on that now the Diagram API call only not working well
I want to know while we calling Diagram API from an React app which props are mandatory
like nodeDataArray,linkDataArray

That depends on which features of GoJS you are using. As a practical matter, I would say that the initDiagram and nodeDataArray are essential, and linkDataArray is essential if you are using a GraphLinksModel.

yeah I use go.GraphLinksModel only

I can give the nodes and links as

diagram.model=new go.GraphLinksModel(nodeDataArray,linkDataArray)

but how do I define initDiagram(),onModelChange(),onDiagramChange(),ModelData
these stuffs

I’m searching for an valid working example of using Diagram API in react but I found nothing useful, please refer any example for quick understanding purpose

Oh, I thought you were using the ReactDiagram component in gojs-react. OK, so I assume you are constructing something yourself using React functional components rather than React classes.

By initDiagram I was referring to the function used to create and initialize the Diagram associated with the HTMLDivElement. That means allocating the Diagram, setting its properties, and setting up its templates and tools and whatever.

But as I said above, I do not think you want to have a pure stateless diagram, because you do not want to re-create and re-initialize the Diagram on each render. For large diagrams that should be obvious, but even for tiny diagrams such re-creation seems quite wasteful. There is a reason that in gojs-react we override shouldComponentUpdate and componentDidUpdate.

I got some inputs but if there is any example,it will very helpful and and easy to understand

Here’s a very basic example demonstrating how you can use a ReactDiagram within a functional component. I’m not sure if this is exactly what you’re looking for, but it serves to demonstrate that gojs-react can be used in the context of React hooks.

If you want to rewrite the ReactDiagram component to use hooks, that will be up to you. You may be interested in how the component is implemented: https://github.com/NorthwoodsSoftware/gojs-react/blob/master/IMPLEMENTATION.md

yeah it is very useful but I need an example of without using <ReactDiagram/> component

var myDiagram = $(go.Diagram, "myDiagramDiv",  // create a Diagram for the DIV HTML element
    {
      "undoManager.isEnabled": true  // enable undo & redo
    });

  // define a simple Node template
  myDiagram.nodeTemplate =
    $(go.Node, "Auto",  // the Shape will go around the TextBlock
      $(go.Shape, "RoundedRectangle", { strokeWidth: 0, fill: "white" },
        // Shape.fill is bound to Node.data.color
        new go.Binding("fill", "color")),
      $(go.TextBlock,
        { margin: 8, font: "bold 14px sans-serif", stroke: '#333' }, // Specify a margin to add some room around the text
        // TextBlock.text is bound to Node.data.key
        new go.Binding("text", "key"))
    );

  // but use the default Link template, by not setting Diagram.linkTemplate

  // create the model data that will be represented by Nodes and Links
  myDiagram.model = new go.GraphLinksModel(
    [
      { key: "Alpha", color: "lightblue" },
      { key: "Beta", color: "orange" },
      { key: "Gamma", color: "lightgreen" },
      { key: "Delta", color: "pink" }
    ],
    [
      { from: "Alpha", to: "Beta" },
      { from: "Alpha", to: "Gamma" },
      { from: "Beta", to: "Beta" },
      { from: "Gamma", to: "Delta" },
      { from: "Delta", to: "Alpha" }
    ]);
  return (
    <div id='myDiagramDiv' style={{width:'600px',height:'600px',border:'1px solid black'}}/>
  );

like this ,this code is not working in react

Your myDiagramDiv div must exist before the diagram can be attached to it. You’ll need React’s useEffect. https://reactjs.org/docs/hooks-effect.html