在 .map() 函数中为每个组件绑定 onClick

IT技术 reactjs
2021-05-07 12:27:31

我创建了一个父组件PicturesFetch,它呈现另一个(子)组件,Picture它呈现一个里面有图片的 div。现在,要渲染PicturePicturesFetch遍历一个对象(图片)并使用 .map() 函数创建多个带有图像的 div。我希望能够更改单独创建的每个元素的状态。这是我到目前为止尝试过的,测试的绑定是一个一个尝试的,而不是全部一起尝试:

图片获取.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>
    );
}}

图片.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>
    )
}}

我简化了示例代码。现在,通过将绑定放置在位置 #1 和 #2 一起更改所有图像状态,而在 #3 中给我错误无法读取 undefined 的属性 'setState'

哪个是绑定 onClick 函数的正确位置,以便我可以分别访问每个图像状态?也许我的结构有缺陷?先感谢您。

3个回答

您可以使用 #1 或 #3 来绑定 onClick 函数。在 #3 中,您在 handlePictureClick 中缺少此内容。

对于第二部分,分别访问每个图像状态。您必须将 isSelected 和 pictureClassName 键放在每个 pic 对象中。和 handlePictureClick 可以修改如下。

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

添加到@dulwalanise 给出的解决方案中,可以通过将 map 函数绑定到上下文来解决问题。this.handlePictureClick未定义,因为这里this指的不是组件的上下文,而是 map 内部的函数

用这个

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

我认为您应该使用第一个绑定选项。

您的 isSelected 布尔值由您所有的子图片共享,因此当 iselected 为 true 时,它​​适用于您的所有图片组件。

我在这里做了一个工作小提琴

class PicturesFetch extends React.Component {
constructor(props) {
super(props);
    this.state = { 
        selected: null,
        pictureClassName: "picture-div green",
        pics : [{name : '1'},{name : '2'},{name : '3'},{name : '4'}]
    };
this.handlePictureClick = this.handlePictureClick.bind(this); /*#1      tested bind*/
}
handlePictureClick (itemSelected){    
console.log(itemSelected)
    this.setState({
        selected: itemSelected,
        pictureClassName: "picture-div green"
    }) 
 }
render() {
   var changeClass = this.state.pictureClassName;
   var selected = this.state.selected;
   var click = this.handlePictureClick;
   var pics = this.state.pics.map((pic, i) => {    
   var itemSelected = selected && selected.name ===       pic.name;
        return (
        <div className="pic-div" key={i} >
            <Picture 
                isSelected={itemSelected}
                pictureClassName={changeClass}
                onClick={click}
                pic={pic}
            />
        </div>
        );
     });
return (
   <div className="Options-container">
      <div className="container">{pics}</div>
   </div>
  )
 }}
class Picture extends React.Component  {
  constructor(props) {
  super(props);     
  }
  render() {
    var pictureClassName = this.props.pictureClassName;
    console.log(this.props.isSelected)
    return (
    <div onClick={ () => this.props.onClick(this.props.pic)}     className={pictureClassName}>
        <h5>{this.props.pic.name}  {this.props.isSelected ? 'selected'    : 'not selected'}</h5>
      </div>
    )
 }}

我希望它对你有帮助