Yuri Visovsiouk Yuri Visovsiouk - 9 days ago 5
React JSX Question

Binding onClick for each Component in a .map() function

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.

Answer

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>
        );
}
Comments