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.