Broken Rendering with Redux + Model Serialization/De-Serialization
Author: jamal-ahmadCreated Sep 19, 2020Updated Apr 2, 2025
Labelsquestionanswered
So i'm trying to setup a simple app with redux as the global store.
The graph is stored in a slice as a simple serialized model object.
On every change to the DiagramModel entities (nodes, links), the DiagramModel is serialized and written back into the store.
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import createEngine, { DiagramModel } from "@projectstorm/react-diagrams";
import { CanvasWidget } from "@projectstorm/react-canvas-core";
import { setGraph, fetchGraph } from "../features/graph/graphSlice";
import { RootState } from "./rootReducer";
import { SimpleSerializedGraph } from "../features/graph/types/simple";
import "./App.css";
const App: React.FC = () => {
console.log("I got called");
const [engine, setEngine] = useState(createEngine());
const dispatch = useDispatch();
const graph: SimpleSerializedGraph = useSelector(
(state: RootState) => state.graph
);
// emulate graph data being loaded from the server
useEffect(() => {
console.log("loading graph");
dispatch(fetchGraph());
}, []);
let model = new DiagramModel();
let obj: ReturnType<DiagramModel["serialize"]> = JSON.parse(
JSON.stringify(graph)
);
model.deserializeModel(obj, engine);
console.log(model.serialize());
model.getModels().forEach((item) =>
item.registerListener({
eventDidFire: () => {
console.log("WOOSH");
dispatch(setGraph(engine.getModel().serialize()));
},
})
);
engine.setModel(model);
return (
<React.Fragment>
<CanvasWidget className="diagram-container" engine={engine} />
</React.Fragment>
);
};
export default App;However this is resulting in very broken rendering. (see pic below). I've got a couple of questions:
- Is there something that i'm doing wrong here?
- if a state management solution is used, how is that global state supposed to be updated?
- Should I store something else in the store e.g. the
ModelEngineobject itself? not sure how feasible that would be with redux - is redux not a good choice for react-diagrams? maybe something like mobx or react context? I hope this isn't the case because redux tooling is very nice and it would be shame if the react-diagrams and redux were at odds.

the dummy data being used is as follows:
export const initialData: SimpleSerializedGraph = {
"id": "initialData",
"offsetX": 0,
"offsetY": 0,
"zoom": 100,
"gridSize": 0,
"layers": [],
}
export const dummyData: SimpleSerializedGraph = {
"id": "dummyData",
"offsetX": 0,
"offsetY": 0,
"zoom": 100,
"gridSize": 0,
"layers": [
{
"id": "28",
"type": "diagram-links",
"isSvg": true,
"transformed": true,
"models": {
"36": {
"id": "36",
"type": "default",
"source": "32",
"sourcePort": "33",
"target": "34",
"targetPort": "35",
"points": [
{
"id": "37",
"type": "point",
"x": 147.234375,
"y": 133.5
},
{
"id": "38",
"type": "point",
"x": 409.5,
"y": 133.5
}
],
"labels": [],
"width": 3,
"color": "gray",
"curvyness": 50,
"selectedColor": "rgb(0,192,255)",
}
}
},
{
"id": "30",
"type": "diagram-nodes",
"isSvg": false,
"transformed": true,
"models": {
"32": {
"id": "32",
"type": "default",
"x": 100,
"y": 100,
"ports": [
{
"id": "33",
"type": "default",
"x": 139.734375,
"y": 126,
"name": "Out",
"alignment": "right",
"parentNode": "32",
"links": [
"36"
],
"in": false,
"label": "Out"
}
],
"name": "Node 1",
"color": "rgb(0,192,255)",
"portsInOrder": [],
"portsOutOrder": [
"33"
]
},
"34": {
"id": "34",
"type": "default",
"x": 400,
"y": 100,
"ports": [
{
"id": "35",
"type": "default",
"x": 402,
"y": 126,
"name": "In",
"alignment": "left",
"parentNode": "34",
"links": [
"36"
],
"in": true,
"label": "In"
}
],
"name": "Node 2",
"color": "rgb(192,255,0)",
"portsInOrder": [
"35"
],
"portsOutOrder": []
}
}
}
]
}and the types being used are (i deduced them from the lib source code):
export interface SimpleSerializedBaseModel {
type: string;
selected?: boolean;
extras?: any;
id: string;
locked?: boolean;
};
// this will allow abitrary proeprties to be added to the model
// as along as the base properties are present
export interface SimpleSerializedModel extends SimpleSerializedBaseModel {
[prop: string]: any;
};
export interface SimpleSerializedLayer {
isSvg: boolean;
transformed: boolean;
models: { [x: string]: SimpleSerializedModel };
type: string;
selected?: boolean;
extras?: any;
id: string;
locked?: boolean;
}
export interface SimpleSerializedGraph {
offsetX: number;
offsetY: number;
zoom: number;
gridSize: number;
layers: SimpleSerializedLayer[];
id: string;
locked?: boolean;
};Source: projectstorm/react-diagrams