projectstorm / react-diagrams

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

Getting this error: TypeError: Cannot read property 'setMaxNumberPointsPerLink' of null #291

Open ahsanbagwan opened 6 years ago

ahsanbagwan commented 6 years ago

I've my code in componentWillMount like so,

componentWillMount() {
    var engine = ...
    ....
    this.setState({engine: engine});
}

I want my Redux props in componentWillMount but during exection of the lifecycle method componentWillMount the async prop is empty.

Whenever I change componentWillMount to componentDidMount I get the following error. Why does this likely happen?

TypeError: Cannot read property 'setMaxNumberPointsPerLink' of null
    at DiagramWidget.render (main.js:1)
    at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (ReactCompositeComponent.js:796)
    at ReactCompositeComponentWrapper._renderValidatedComponent (ReactCompositeComponent.js:819)
    at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:359)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:255)
    at Object.mountComponent (ReactReconciler.js:43)
    at ReactDOMComponent.mountChildren (ReactMultiChild.js:234)
    at ReactDOMComponent._createInitialChildren (ReactDOMComponent.js:701)
    at ReactDOMComponent.mountComponent (ReactDOMComponent.js:520)
    at Object.mountComponent (ReactReconciler.js:43)
Smolyan91 commented 6 years ago

I have a similar problem. I tried to solve her of two ways.

It's first:

import * as React from "react";
import {
    DiagramEngine,
    DiagramModel,
    DiagramProps,
    DefaultNodeModel,
    LinkModel,
    DiagramWidget
} from "storm-react-diagrams";

export default class Test extends React.Component{

    constructor(props) {
        super(props);

        const engine = new DiagramEngine();
        engine.installDefaultFactories();
        engine.setMaxNumberPointsPerLink(200);
        this.state = {engine};
    }

    componentDidMount() {
        const {engine} = this.state;
        const model = new DiagramModel();

        const node1 = new DefaultNodeModel("Node 1", "rgb(255,99,66)");
        const port1 = node1.addOutPort("Out");
        node1.setPosition(100, 100);

        const node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
        const port2 = node2.addInPort("In");
        node2.setPosition(400, 40);

        const node3 = new DefaultNodeModel("Node 3", "rgb(128,99,255)");
        const port3 = node3.addInPort("In");
        node3.setPosition(300, 160);

        const link1 = port1.link(port2);
        const link2 = port1.link(port3);

        const models = model.addAll(node1, node2, node3, link1, link2);

        models.forEach(item => {
            item.addListener({...});
        });

        engine.setDiagramModel(model);

        this.setState({
            diagramEngine: engine,
        });
    }

    render (){
        return (
            <div>
                <p>Click the diagram elements to inspect some of the possible events.</p>
                <DiagramWidget className="srd-demo-canvas" {...this.state} />
            </div>
        );
    }
};

It's second way (how in tutorial):

import * as React from "react";
import {
    DiagramEngine,
    DiagramModel,
    DiagramProps,
    DefaultNodeModel,
    LinkModel,
    DiagramWidget
} from "storm-react-diagrams";

export default class Test extends React.Component{

    constructor(props) {
        super(props);

        const engine = new DiagramEngine();
        engine.installDefaultFactories();
        this.state = {engine};
    }

    componentDidMount() {
        const {engine} = this.state;
        const model = new DiagramModel();

        const node1 = new DefaultNodeModel("Node 1", "rgb(255,99,66)");
        const port1 = node1.addOutPort("Out");
        node1.setPosition(100, 100);

        const node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
        const port2 = node2.addInPort("In");
        node2.setPosition(400, 40);

        const node3 = new DefaultNodeModel("Node 3", "rgb(128,99,255)");
        const port3 = node3.addInPort("In");
        node3.setPosition(300, 160);

        const link1 = port1.link(port2);
        const link2 = port1.link(port3);

        const models = model.addAll(node1, node2, node3, link1, link2);

        models.forEach(item => {
            item.addListener({...});
        });

        engine.setDiagramModel(model);

        this.setState({
            diagramEngine: engine,
                         maxNumberPointsPerLink: 0
        });
    }

    render (){
        return (
            <div>
                <p>Click the diagram elements to inspect some of the possible events.</p>
                <DiagramWidget className="srd-demo-canvas" {...this.state} />
            </div>
        );
    }
};

But I got anytime this error: TypeError: Cannot read property 'setMaxNumberPointsPerLink' of null

Uncaught TypeError: Cannot read property 'setMaxNumberPointsPerLink' of null
    at DiagramWidget.render (main.js:1)
    at finishClassComponent (react-dom.development.js:13538)
    at updateClassComponent (react-dom.development.js:13501)
    at beginWork (react-dom.development.js:14090)
    at performUnitOfWork (react-dom.development.js:16416)
    at workLoop (react-dom.development.js:16454)
    at HTMLUnknownElement.callCallback (react-dom.development.js:145)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:195)
    at invokeGuardedCallback (react-dom.development.js:248)
    at replayUnitOfWork (react-dom.development.js:15745)
    at renderRoot (react-dom.development.js:16548)
    at performWorkOnRoot (react-dom.development.js:17387)
    at performWork (react-dom.development.js:17295)
    at performSyncWork (react-dom.development.js:17267)
    at requestWork (react-dom.development.js:17155)
    at scheduleWork (react-dom.development.js:16949)
    at scheduleRootUpdate (react-dom.development.js:17637)
    at updateContainerAtExpirationTime (react-dom.development.js:17664)
    at updateContainer (react-dom.development.js:17691)
    at ReactRoot../node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render (react-dom.development.js:17957)
    at react-dom.development.js:18097
    at unbatchedUpdates (react-dom.development.js:17518)
    at legacyRenderSubtreeIntoContainer (react-dom.development.js:18093)
    at Object.render (react-dom.development.js:18152)
    at Object../src/index.js (index.js:7)
    at __webpack_require__ (bootstrap 4623bd698cff3b082406:678)
    at fn (bootstrap 4623bd698cff3b082406:88)
    at Object.0 (registerServiceWorker.js:117)
    at __webpack_require__ (bootstrap 4623bd698cff3b082406:678)
    at ./node_modules/ansi-regex/index.js.module.exports (bootstrap 4623bd698cff3b082406:724)
    at bootstrap 4623bd698cff3b082406:724
DiagramWidget.render @ main.js:1
finishClassComponent @ react-dom.development.js:13538
updateClassComponent @ react-dom.development.js:13501
beginWork @ react-dom.development.js:14090
performUnitOfWork @ react-dom.development.js:16416
workLoop @ react-dom.development.js:16454
callCallback @ react-dom.development.js:145
invokeGuardedCallbackDev @ react-dom.development.js:195
invokeGuardedCallback @ react-dom.development.js:248
replayUnitOfWork @ react-dom.development.js:15745
renderRoot @ react-dom.development.js:16548
performWorkOnRoot @ react-dom.development.js:17387
performWork @ react-dom.development.js:17295
performSyncWork @ react-dom.development.js:17267
requestWork @ react-dom.development.js:17155
scheduleWork @ react-dom.development.js:16949
scheduleRootUpdate @ react-dom.development.js:17637
updateContainerAtExpirationTime @ react-dom.development.js:17664
updateContainer @ react-dom.development.js:17691
./node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render @ react-dom.development.js:17957
(anonymous) @ react-dom.development.js:18097
unbatchedUpdates @ react-dom.development.js:17518
legacyRenderSubtreeIntoContainer @ react-dom.development.js:18093
render @ react-dom.development.js:18152
./src/index.js @ index.js:7
__webpack_require__ @ bootstrap 4623bd698cff3b082406:678
fn @ bootstrap 4623bd698cff3b082406:88
0 @ registerServiceWorker.js:117
__webpack_require__ @ bootstrap 4623bd698cff3b082406:678
./node_modules/ansi-regex/index.js.module.exports @ bootstrap 4623bd698cff3b082406:724
(anonymous) @ bootstrap 4623bd698cff3b082406:724
index.js:2178 The above error occurred in the <DiagramWidget> component:
    in DiagramWidget (at Test.js:64)
    in div (at Test.js:62)
    in Test (at App.js:11)
    in div (at App.js:10)
    in App (at src/index.js:7)
Smolyan91 commented 6 years ago

This problem solved. Code:

export class Test extends React.Component<*,*> {

    render () {
        const {engine} =  this.props;
        return (
            <React.Fragment>
                <DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />
                <div className="components-container">
                                  ...
                </div>
            </React.Fragment>
        )
    }
}

export default () => {
    const engine = new DiagramEngine();
    engine.installDefaultFactories();
    const model = new DiagramModel();

    var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
    let port1 = node1.addOutPort("Out");
    node1.setPosition(100, 100);
    var node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
    let port2 = node2.addInPort("In");
    node2.setPosition(400, 100);
    let link1 = port1.link(port2);
    link1.setColor('black');
    model.addAll(node1, node2, link1);
    var node3 = new DefaultNodeModel("Node 3", "rgb(192,255,0)");
    node3.addInPort("In");
    node3.addOutPort("out");
    model.addAll(node3);
    engine.setDiagramModel(model);
    return <Test className="srd-demo-canvas" engine={engine} model={model} />;
};

It works. I think, must be mandatory export default () => ... with engine and model .

imgnx commented 5 years ago

Any updates on this? I'm getting this error when trying to render the DiagramWidget inside a React.js component. I'm using Redux and React state to maintain the state of the widget.

Here's basically what I'm trying to do:

import React from "react";
import { connect } from 'react-redux';
import * as SRD from "@projectstorm/react-diagrams";
require("@projectstorm/react-diagrams/dist/style.min.css");

export class Flowchart extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      engine: null,
      model: null
    }
  }
  componentDidMount() {
    const engine = new SRD.DiagramEngine();
    engine.installDefaultFactories();
    const model = new SRD.DiagramModel();

    var node1 = new SRD.DefaultNodeModel("Node 1", "rgb(0,192,255)");
    let port1 = node1.addOutPort("Out");
    node1.setPosition(100, 100);
    var node2 = new SRD.DefaultNodeModel("Node 2", "rgb(192,255,0)");
    let port2 = node2.addInPort("In");
    node2.setPosition(400, 100);
    let link1 = port1.link(port2);
    link1.setColor('black');
    model.addAll(node1, node2, link1);
    var node3 = new SRD.DefaultNodeModel("Node 3", "rgb(192,255,0)");
    node3.addInPort("In");
    node3.addOutPort("out");
    model.addAll(node3);
    engine.setDiagramModel(model);
    this.setState({
      engine: engine,
      model: model
    })
  }
  render() {
    return (
      <React.Fragment>
        <SRD.DiagramWidget className="srd-demo-canvas" diagramEngine={this.state.engine} model={this.state.model} />
        <div className="components-container">
          ...
    </div>
      </React.Fragment>
    )
  }
}

// Not connected yet. Trying to use React.Component.state first before connecting to Redux.
export default Flowchart;
imgnx commented 5 years ago

Fixed

import React from "react";
import * as SRD from "@projectstorm/react-diagrams";
require("@projectstorm/react-diagrams/dist/style.min.css");

export class Storm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      engine: null,
      engineIsInitialized: false,
      model: null
    }
  }
  componentDidMount() {
    const engine = new SRD.DiagramEngine();
    engine.installDefaultFactories();
    const model = new SRD.DiagramModel();

    var node1 = new SRD.DefaultNodeModel("Node 1", "rgb(0,192,255)");
    let port1 = node1.addOutPort("Out");
    node1.setPosition(100, 100);
    var node2 = new SRD.DefaultNodeModel("Node 2", "rgb(192,255,0)");
    let port2 = node2.addInPort("In");
    node2.setPosition(400, 100);
    let link1 = port1.link(port2);
    link1.setColor('black');
    model.addAll(node1, node2, link1);
    var node3 = new SRD.DefaultNodeModel("Node 3", "rgb(192,255,0)");
    node3.addInPort("In");
    node3.addOutPort("out");
    model.addAll(node3);
    engine.setDiagramModel(model);
    this.setState({
      engine: engine,
      model: model,
      engineIsInitialized: true
    })
  }
  render() {
    return (
      <React.Fragment>
      {this.state.engineIsInitialized && (
        <React.Fragment>
          <SRD.DiagramWidget className="srd-demo-canvas" diagramEngine={this.state.engine} model={this.state.model} />
          <span>Hello World</span>
        </React.Fragment>
      )}
        <div className="components-container">
          ...
          </div>
      </React.Fragment>
    )
  }
}

export default Storm;

@dylanvorster You can close this one out. The problem was that the OP was rendering the canvas before it was initialized.