MJS Diagram Documentation: Getting started with React

Getting started with React

In this tutorial we will add a Diagram Editor and a Diagram Viewer to a basic React application.

We will not cover the installation and other basics. For that, please refer to the general getting started tutorial.


In this tutorial we will add both the editor and the viewer to the same React component. Our initial diagram (so you don't get an empty starting point) is stored in the initialDiagram variable, for simplicity. Normally it would come from some kind of storage through the component's props.

Note that this is not a React tutorial and it may not follow the best React practices. The goal here is to show how to include MJS Diagram in a React app with minimal conceptual overhead. For a complete real-life demo implementation checkout the Diagrams app and it's source code.

We are using TypeScript in the code below, but you should be able to easily use the code in plain JavaScript by stripping out the types.

In case you want to jump straight into code, hop over to the complete sample for this tutorial on Codesandbox.

State and refs

MJS Diagram components take up the whole area of their parent container, so we need to setup the placeholders for both the editor and the viewer.

return ( <div className="App"> <div className="diagram-editor" ref={editorContainerRef}></div> <div className="diagram-viewer" ref={viewerContainerRef}></div> </div> );

We define the dimensions of these divs in our CSS and, as you can see, we set refs on these divs so we can refer them in our code. So we define both of these refs in our code:

const viewerContainerRef = useRef<HTMLDivElement>(null); const editorContainerRef = useRef<HTMLDivElement>(null);

As our MJS Diagram components are not React componets, we need to setup refs to refer them as well.

const viewerRef = useRef<DiagramViewer | null>(null); const editorRef = useRef<DiagramEditor | null>(null);

The DiagramViewer class comes from the @markerjs/mjs-diagram/viewer module and DiagramEditor can be found in @markerjs/mjs-diagram/editor.

We will hold our diagram config (also known as diagram state) in our React componet's state. We are passing our "saved" initialDiagram config as the initial state.

const [diagram, setDiagram] = useState<DiagramState>(initialDiagram);

The DiagramState type comes from the @markerjs/mjs-diagram/core module.

We are now ready to setup our editor.

Diagram editor

As our components are "external" to React we are using the useEffect hook to setup and update MJS Diagram components.

As we need to setup the editor just once, we will check if our editorRef is null before proceeding. Then we create a new instance of DiagramEditor and add it as child to a respective div using the editorContainerRef.

We are creating a flowchart editor in this tutorial, so we need to set the editor's stencilEditorSet = flowchartStencilEditorSet. The flowchartStencilEditorSet comes from a flowchart stencilset in @markerjs/mjs-diagram/stencilsets/flowchart/flowchart

When the user clicks on the "save" button in the toolbar saveclick event is fired. We add an event handler for the saveclick event to update our component's state with a new diagram configuration provided in the event's detail.state property.

Finally, we need to restore our saved state in the editor using its restoreState method.

Here's the complete code for our editor-related hook:

useEffect(() => { if (editorRef.current === null) { const editor = new DiagramEditor(); editorContainerRef.current?.appendChild(editor); editorRef.current = editor; editor.addEventListener("saveclick", (ev) => { setDiagram(ev.detail.state); }); editorRef.current.stencilEditorSet = flowchartStencilEditorSet; } editorRef.current.restoreState(diagram); }, []);

Diagram viewer

Adding the viewer is almost identical to the editor. Instead of the DiagramEditor we instantiate a DiagramViewer, we don't need to handle any events, and we set a stencilSet = flowchartStencilSet (instead of stencilEditorSet).

Finally, we call the viewer's show() method to pass our diagram's config. And we shouldn't forget to pass our diagram state variable as a dependency for the hook, so that it's rerendered when the diagram is edited and saved.

Here's the complete useEffect hook for the diagram viewer:

useEffect(() => { if (viewerRef.current === null) { const viewer = new DiagramViewer(); viewerContainerRef.current?.appendChild(viewer); viewerRef.current = viewer; viewerRef.current.stencilSet = flowchartStencilSet; } viewerRef.current.show(diagram); }, [diagram]);

The complete demo

That is all it takes and below is this demo in action. Try editing the diagram and click save to see the changes reflected in the lower (viewer) part.

Check this demo out and fork it on Codesandbox.

See also

Diagrams app is a complete real-life React (Next.js) MJS Diagram implementation. The source code is available on GitHub.