projectstorm / react-diagrams

a super simple, no-nonsense diagramming library written in react that just works
https://projectstorm.cloud/react-diagrams
MIT License
8.45k stars 1.16k forks source link

Node not getting added with useEffect #973

Open abhisheksarka opened 1 year ago

abhisheksarka commented 1 year ago

Hi,

I have been trying to make this work with useEffect as follows

import createEngine, { 
  DefaultLinkModel, 
  DefaultNodeModel,
  DefaultLabelModel,
  DiagramModel, 
  LabelModel
} from '@projectstorm/react-diagrams';
import { useSelector } from 'react-redux'
import styles from './Diagram.module.scss';

import {
  CanvasWidget
} from '@projectstorm/react-canvas-core';
import styled from '@emotion/styled';
import { useEffect } from 'react';
import { drawEdge, drawNode } from './reducer';

const FullscreenCanvas = styled(CanvasWidget)`
  height: 100%;
  width: 100%;
`;

export default function Diagram(props) {
  const nodes = useSelector((state) => state.nodes);
  const engine = createEngine();
  const model = new DiagramModel();
  engine.setModel(model);

  useEffect(() => {
    nodes.forEach(node => {
      addNode({
        name: node.name,
        color: 'rgb(0,192,255)'
      })
    });

    engine.repaintCanvas();
  }, [nodes]);

  function addNode(attrs) {
    const node = new DefaultNodeModel(attrs);
    node.setPosition(100, 100);
    model.addAll(node); 
  }

  return (
    <>
      <div className={styles['diagram-container']}>
        <FullscreenCanvas engine={engine} />
      </div>
    </>

  )
}

Instead of useEffect if I call addNode function onClick of a button and then repaintCanvas, it works

Is anything extra required in case of useEffect? Thanks in advance!

Marshall200900 commented 1 year ago

Seems like everything is ok in your example, so my theory is that there are problems with redux. If you have not solved the problem yet, you can send a link to a sandbox.

vxlk commented 1 year ago

what type is nodes?

if it is an array or object the dependency array will use referential comparison. so if you did not swap the object and instead just mutated it, the effect may not be running.

quick fix:

use [JSON.stringify(nodes)] in the dep array

jameswest368 commented 1 year ago

I've got it working with a useRef

...
const engine = createEngine();
const model = useRef(new DiagramModel());
engine.setModel(model.current);
...

then when you need to interact with model from a hook then you can:

model.current.addAll(node);