1

I want to render an array of React components with the help of KonvaJs without knowing exactly which object I draw at a particular moment. To be more specific, here is my code:

One of the React components I want to render, wall.js:

class CWall extends React.Component {
 render() {
    return (
      <React.Fragment>
        <Rect /*some props*/></Rect>
        <Transformer /*some props*/></Transformer>
      </React.Fragment>
    )
  }
}

In the other component I create CWall when the button is clicked, planmenu.js:

class PlanMenu extends React.Component {
  render() {
    ...
    return (
    ...
        <button type="button"
          onClick={() => { addObject(
            new CWall({
                x: 100,
                y: 100,
                length: 200
            }))}}>Wall
        </button>
    )
  }
}

The created objects are passed to the component which should display them, planbuilder.js:

import CWall from './objects/wall'

class PlanBuilder extends React.Component {
  render() {
    const { objects } = this.props
    return (
      <Stage>
        <Layer>
          {
            objects.map(function(object) {
              var ObjectType = object.constructor.name;
              /* the following line gives an error to me */
              return <ObjectType {...object.props} key={object.id} />;
            }, this)
          }
        </Layer>
      </Stage>
    );
  }
}

The specified line throws an error:

konva has no node with the type CWall

However, if I render one CWall directly, I get it on the screen as expected. It seems to me like evidence that konva is able to render CWall objects:

class PlanBuilder extends React.Component {
  render() {
    const { objects } = this.props
    return (
      <Stage>
        <Layer>
          <CWall x={100} y={100} length={200} />
        </Layer>
      </Stage>
    );
  }
}

So my question is: what is the proper way of rendering objects without knowing their exact types? Thank you in advance.

kasom
  • 43
  • 4

2 Answers2

2

In general, you should not add React components directly into the state. Instead, just add pure data about your app, and then just render from that data. It can be like this:

class PlanMenu extends React.Component {
  render() {
    ...
    return (
    ...
        <button type="button"
          onClick={() => { addObject({ x: 10, y: 10, type: 'wall' })}}
        </button>
    )
  }
}


import CWall from './objects/wall'


const TYPES = {
   'wall' : CWall
};

class PlanBuilder extends React.Component {
  render() {
    const { objects } = this.props
    return (
      <Stage>
        <Layer>
          {
            objects.map(function(object) {
              const Component = TYPES[object.type];
              return <Component {...object} key={object.id} />;
            }, this)
          }
        </Layer>
      </Stage>
    );
  }
}
lavrton
  • 18,973
  • 4
  • 30
  • 63
1

You can use array of JSX.Element, when button clicks you will create JSX.Element and push it to array of JSX.Element and then put array into render for example

<button type="button"
    onClick={() => { addObject(
    <CWall
        x: 100,
        y: 100,
        length: 200
    />)}
</button>
render() {
    const { objects } = this.props
        return (
            <Stage>
                <Layer>
                    {objects}
                </Layer>
            </Stage>
        );
}
dungmv
  • 11
  • 1