I have a created a parent component PicturesFetch
that renders another (children) component, Picture
which renders a div with a picture inside. Now, to render Picture
, PicturesFetch
goes through an object (pics) and with a .map() function creates multiple divs with images inside. I want to be able to change the state of each element created separately. Here is what I tried so far, the tested binds were tried one by one, not all together:
PictureFetch.js
class PicturesFetch extends React.Component {
constructor(props) {
super(props);
this.state = {
isSelected: true,
pictureClassName: "picture-div green",
pics : [/*Object witch contains names and src of the images*/]
};
this.handlePictureClick = this.handlePictureClick.bind(this); /*#1 tested bind*/
}
handlePictureClick (isSelected){
if (!isSelected) {
this.setState({
isSelected: true,
pictureClassName: "picture-div green"
})
} else {
this.setState({
isSelected: false,
pictureClassName: "picture-div none"
})
}
}
render() {
var changeClass = this.state.pictureClassName;
var handlePictureClick = this.handlePictureClick.bind(this); /*#2 tested bind*/
var pics = this.state.pics.map(function(pic, i){
if (/*something*/) {
return (
<div className="pic-div" key={i} >
<Picture
isSelected={isSelected}
pictureClassName={changeClass}
onClick={handlePictureClick.bind(this, isSelected)} /*#3 tested bind*/
/>
</div>
});
}
return (
<div className="Options-container">
<div className="container">{pics}</div>
</div>
);
}}
Picture.js
class Picture extends React.Component {
constructor(props) {
super(props);
this.state = {
isSelected: true,
pictureClassName: "picture-div green"
};
}
render() {
var pictureClassName = this.props.pictureClassName;
return (
<div onClick={this.props.onClick} className={pictureClassName}>
<img src={this.props.src} alt={this.props.name} />
<h5>{this.props.name}</h5>
</div>
)
}}
I simplified my code for the example. Now, by placing the bind in positions #1 and #2 changes all the images state together, while in #3 gives me the error Cannot read property 'setState' of undefined.
Which is the correct place to bind the onClick function so I can access each image state separately? Maybe my structure is flawed? Thank you in advance.
The first solution to perform multiple onClick events in React is to include all of your actions inside of a function and then call that single function from the onClick event handler. Let's explore how to do that in a React Component: import React from 'react'; function App() { function greeting() { console.
Example: Updating the State in an onClick Event Handler A very common use of an inline function inside of an onClick event handler in React is to update a component's state. import React, { Component } from 'react'; class App extends Component { constructor(props) { super(props); this.
you can simply pass the state with some name <Button name={stateValue}> and use it in your child component.
You can use either #1 or #3 to bind onClick function. Here in #3 you are missing this in handlePictureClick.
and for the second part accessing each image state separately. you will have to put the isSelected and pictureClassName key inside each pic object. and handlePictureClick can be modified as below.
handlePictureClick (pic){
this.setState(pics : this.state.pics.map(function(picture){
if(picture.id === pic.id){
if(picture.isSelected){
picture.isSelected = false;
picture.pictureClassName = "picture-div none";
} else {
picture.isSelected = true;
picture.pictureClassName = "picture-div green";
}
}
return picture;
));
}
render() {
var changeClass = this.state.pictureClassName;
var pics = this.state.pics.map(function(pic, i) {
if (/*something*/) {
return (
<div className="pic-div" key={i} >
<Picture
isSelected={pic.isSelected}
pictureClassName={changeClass}
onClick={this.handlePictureClick.bind(this, pic)}
/>
</div>
}
});
return (
<div className="Options-container">
<div className="container">{pics}</div>
</div>
);
}
Adding to the solution given by @dulwalanise the problem can be solved by bind the map function to the context. this.handlePictureClick
is undefined because here this
doesn't refer to the context of the component rather the function inside of map
use this
handlePictureClick (pic){
this.setState(pics : this.state.pics.map(function(picture){
if(picture.id === pic.id){
if(picture.isSelected){
picture.isSelected = false;
picture.pictureClassName = "picture-div none";
} else {
picture.isSelected = true;
picture.pictureClassName = "picture-div green";
}
}
return picture;
));
}
render() {
var changeClass = this.state.pictureClassName;
var pics = this.state.pics.map(function(pic, i) {
if (/*something*/) {
return (
<div className="pic-div" key={i} >
<Picture
isSelected={pic.isSelected}
pictureClassName={changeClass}
onClick={this.handlePictureClick.bind(this, pic)}
/>
</div>
}
}.bind(this));
return (
<div className="Options-container">
<div className="container">{pics}</div>
</div>
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With