Skip to main content
  1. Index

Using GoJS with React

Examples of most of the topics discussed on this page can be found in the gojs-react-basic project, which serves as a simple starter project.

If you are new to GoJS, it may be helpful to first visit the Quick Start Tutorial.

The easiest way to get a component set up for a GoJS Diagram is to use the gojs-react package, which exports React Components for GoJS Diagrams, Palettes, and Overviews. The gojs-react-basic project demonstrates how to use these components. More information about the package, including the various props it takes, can be found on the Github or NPM pages. Our examples will be using a GraphLinksModel, but any model can be used.

Quick start with an existing React application

Installation

Start by installing GoJS and gojs-react: npm install gojs gojs-react.

Diagram styling

Next, set up a CSS class for the GoJS diagram's div:

css

Rendering the component

Finally, add an initDiagram function and a model change handler function, and add the ReactDiagram component inside your render method. Note that the UndoManager should always be enabled to allow for transactions to take place, but the UndoManager.maxHistoryLength can be set to 0 to prevent undo and redo.

js

That's it! You should now have a GoJS diagram rendering within your React application. Try editing the text of a node or deleting a node, and you'll see an alert on the page.

Adding interactivity

The above example shows a simple event handler for onModelChange. While more advanced handlers can be used to effectively communicate the Diagram's changes to the app, one might want ways to communicate from the app to the Diagram, and to also have those changes persist across rerenders.

To do this, we can make the Link and Node data arrays stateful, in a React sense. While useState works, you either need several calls or complex setters. Instead, all arguments to ReactDiagram that you wish to update later can stored in a useImmer or similar hook, and then passed to the diagram:

jsx

Now that your Diagram's data is stateful, any component with access to updateDiagramData can call it and make changes that will persist across rerenders:

jsx

Updating state

Because React state is immutable, it cannot be directly reassigned. Updating state works normally for most properties of ReactDiagram, but not all. When a property like skipsDiagramUpdate is updated with updateDiagramData, the new value is passed into ReactDiagram and simply replaces the old one.

But, when nodeDataArray or linkDataArray are updated with updateDiagramData, the new value is passed into ReactDiagram and instead of replacing the old one, will be merged with Diagram.mergeNodeDataArray or Diagram.mergeLinkDataArray. Here are some suggested patterns when performing common operations on these properties.

Adding/modifying Node properties

jsx

Removing Node properties

GoJS avoids destructive merging; this means properties must be explicitly set to undefined in order to remove them when merging:

jsx

Adding Nodes

jsx

Removing Nodes

jsx

ModelData

When modelData is modified, its new value will be merged with the old one via Model.assignAllDataProperties.

Usage in a multi-component React app

Now that your Diagram's state is "wired in" with React, we can apply common React design patterns to create an app where users can change whether or not relinking is allowed on a Diagram.

A basic setup can be seen in the gojs-react-basic project, but we'll describe some of the methodology here.

First, we will take our Diagram wrapper from earlier and add more functionality to it:

  • a set of props coming in from the parent component which holds state and handlers
  • a ref to the ReactDiagram component so getDiagram() and clear() can be used
  • a useEffect to add/remove app-specific diagram listeners

This would be the new outline for the wrapper:

jsx

And this will be the outline for the App component:

jsx

Below is our finished Diagram wrapper. We pass linkDataArray and modelData as props to the ReactDiagram, but note that they are not always needed in gojs-react components, so your app may not need to include them. For proper initial loading of data, one should have the data ready before the ReactDiagram component mounts. This allows layouts and linking to occur properly with the initial data set.

Some important details in this, and in the full example in the gojs-react-basic project, include management of skipsDiagramUpdate, the setting of GraphLinksModel.linkKeyProperty, and the GraphLinksMode.makeUniqueKeyFunction and GraphLinksModel.makeUniqueLinkKeyFunction.

tsx

Using the wrapper component within the app

The application should set up a few things to be passed to the wrapper described above:

  • state containing a nodeDataArray, linkDataArray, modelData object, and skipsDiagramUpdate flag
  • a handleDiagramEvent function for any app-specific DiagramEvents, such as 'ChangedSelection'
  • a handleModelChange function for updating state based on updates from the GoJS model

tsx

A note on Diagram reinitialization

Occasionally you may want to treat a model update as if you were loading a completely new model. But initialization is done via the initDiagram function and only when the ReactDiagram mounts, meaning that even merging an entirely new model would not reinitialize the Diagram.

To address this problem, ReactDiagram exposes a clear() method. When called, it clears its diagram of all nodes, links, and model data, and prepares the next state update to be treated as a diagram initialization. That will result in an initial layout and perform initial diagram content alignment and scaling. Note that the initDiagram function is not called again.

Here is a small sample of how one might trigger diagram reinitilization using the clear() method.

js

These are the basics for setting up GoJS within a React application. See gojs-react-basic for a working example and the gojs-react Github page for further explanation of various props passed to the components.