简体   繁体   中英

React add Component as a variable

I have a simple problem to solve. I've created a react app using npx create-react-app . I made a Map component, which I add to my view with this:

class App extends Component {
    render() {
        return (
            <div className="App">
                <header className="App-header">
                    <img src={logo} className="App-logo" alt="logo" />
                    <h1 className="App-title">Welcome to React</h1>
                </header>
                <p className="App-intro">
                    To get started, edit <code>src/App.js</code> and save to reload.
                </p>
                <p>
                    <Map />
                </p>
            </div>
        );
    }
}

And the Map component appears. Now I want to have a button which has an onClick method which calls Map.addImage . First of all it cannot be static (addImage uses Map members, which have to be initialized in constructor). The problem is I know I would have to do var map = new Map() . And then <button type="button" onClick={map.addImage} /> but how can I make my map appear? I cannot go for:

<p>
    <map />
</p>

So the question is how can I make my map (after var map = new Map() in render() method, above the return) appear on the screen?

@Edit

Map implementation:

export default class Map extends React.Component {

    constructor(props) {
        super(props);
        this.stage = null;
        this.layer = null;
    }
    componentDidMount() {
        //const tween = null;

        this.stage = new Konva.Stage({
            container: this.containerRef,
            width: 1024,
            height: 600
        });


        this.layer = new Konva.Layer();
        //const dragLayer = new Konva.Layer();

        this.stage.add(this.layer);

        /*stage.on("dragstart", function (evt) {
            const shape = evt.target;
            // moving to another layer will improve dragging performance
            shape.moveTo(dragLayer);
            stage.draw();

            if (tween) {
                tween.pause();
            }
            shape.setAttrs({
                shadowOffset: {
                    x: 15,
                    y: 15
                },
                scale: {
                    x: shape.getAttr("startScale") * 1.2,
                    y: shape.getAttr("startScale") * 1.2
                }
            });
        });

        stage.on("dragend", function (evt) {
            const shape = evt.target;
            shape.moveTo(layer);
            stage.draw();
            shape.to({
                duration: 0.5,
                easing: Konva.Easings.ElasticEaseOut,
                scaleX: shape.getAttr("startScale"),
                scaleY: shape.getAttr("startScale"),
                shadowOffsetX: 5,
                shadowOffsetY: 5
            });
        });*/
    }

    render() {
        return (
            <div
                className="container"
                ref={ref => {
                    console.log(ref);
                    this.containerRef = ref;
                }}
            />
        );
    }

    addImage() {
        var imageObj = new Image();
        imageObj.src = './box.png';
        imageObj.misc = { stage: this.stage, layer: this.layer };
        console.log(this.stage)
        imageObj.onload = function () {
            var image = new Konva.Image({
                x: Math.random() * this.misc.stage.getWidth(),
                y: Math.random() * this.misc.stage.getHeight(),
                width: 100,
                height: 100,
                image: imageObj,
                draggable: true
            });
            this.misc.layer.add(image);
            this.misc.layer.draw();
        };
    }
}

As Oblosys said, you generally don't want to try to do this in React. If you must, go with the ref route. It's there for a reason.

But I would suggest considering lifting the images up to your App state and passing them down as props. It's hard to say what this would look like as you have not provided an implementation for the Map component, but it would look something like this.

class App extends Component {
  constructor() {
    super();
    this.state = { images: [] };
    this.addImage = this.addImage.bind(this);
  }

  addImage() {
    const newImage = 5; // I obviously have no idea what this actually looks like
    this.setState(({ images }) => ({ images: [...images, newImage] }));
  }

  render() {
    return (
      <div className="App">
         <header className="App-header">
           <img src={logo} className="App-logo" alt="logo" />
           <h1 className="App-title">Welcome to React</h1>
         </header>
         <p className="App-intro">
           To get started, edit <code>src/App.js</code> and save to reload.
         </p>
         <p>
           <Map images={this.state.images} />
         </p>
         <button onClick={this.addImage}>Add an image</button>
       </div>
     );
  }
}

This won't work well in all cases (for example, if you're using a third party tool in Map ), but this is more The React Way.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM