简体   繁体   English

如何处理ReactJS中数组对象的onClick事件?

[英]How to handle onClick events for array objects in ReactJS?

I am trying to add an onClick event handler to objects in an array where the class of a clicked object is changed, but instead of only changing one element's class, it changes the classes of all the elements. 我试图将一个onClick事件处理程序添加到更改了单击对象的类的数组中的对象上,但是它不仅更改了一个元素的类,而且还更改了所有元素的类。

How can I get the function to work on only one section element at a time? 如何使函数一次只能在一个section元素上工作?

class Tiles extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            clicked: false,
            content : []
        };
    this.onClicked = this.onClicked.bind(this);

componentDidMount() {
    let url = '';
    let request = new Request(url, {
        method: 'GET',
        headers: new Headers({
            'Content-Type': 'application/json'
        })
    });
    fetch(request)
    .then(response => response.json())
    .then(data => {
        this.setState({
            content : data
        })
    } );

}

onClicked() {
    this.setState({
        clicked: !this.state.clicked
        });
}

render() {
    let tileClass = 'tile-content';
    if (this.state.clicked) {
        tileClass = tileClass + ' active'
    }
    return (
    <div className = 'main-content'>
    {this.state.pages.map((item) => 
        <section key = {item.id} className = {tileClass} onClick = {this.onClicked}>
        <h4>{item.description}</h4>
        </section>)}
        <br />
    </div>
    )
 }

class App extends React.Component {
    render() {
       return (
        <div>
            <Tiles />
        </div>
       )
 }
}

ReactDOM.render(
     <App />,
    document.getElementById('content-app'))

It is happening for you, because you are assigning active class to all sections once user clicked on one of them. 这是为您而发生的,因为一旦用户单击其中的一个,就将为所有部分分配活动类。 You need somehow to remember where user clicked. 您需要某种方式来记住用户单击的位置。 So I suggest you to use array, where you will store indexes of all clicked sections. 因此,我建议您使用数组,其中将存储所有单击部分的索引。 In this case your state.clicked is an array now. 在这种情况下,您的state.clicked现在是一个数组。

onClicked(number) {
  let clicked = Object.assign([], this.state.clicked);
  let index = clicked.indexOf(number);
  if(index !== -1) clicked.splice(index, 1);
  else clicked.push(number)
  this.setState({
    clicked: clicked
  });
}

render() {
  let tileClass = 'tile-content';
  return (
    <div className = 'main-content'>
      {this.state.pages.map((item, i) => { 
        let tileClass = 'tile-content';
        if(this.state.clicked.includes(i)) tile-content += ' active';
        return (
          <section key = {item.id} className = {tileClass} onClick = {this.onClicked.bind(this, i)}>
            <h4>{item.description}</h4>
          </section>
        )
      })}
      <br />
    </div>
  )

} }

state.pages need to keep track of the individual click states, rather than an instance-wide clicked state state.pages需要跟踪单个单击状态,而不是实例范围内的单击状态

your onClick handler should accept an index, clone state.pages and splice your new page state where the outdated one used to be 您的onClick处理程序应接受索引,克隆state.pages并将新的页面状态拼接到以前已经过时的状态

you can also add data-index to your element, then check onClick (e) { e.currentTarget.dataset.index } to know which page needs to toggle clickstate 您还可以将data-index添加到您的元素,然后检查onClick (e) { e.currentTarget.dataset.index }以了解哪个页面需要切换clickstate

StackOverflow does a particularly poor job of code in comments, so here's the implementation of onClicked from @Taras Danylyuk using the callback version of setState to avoid timing issues: StackOverflow在注释代码方面做得特别差,因此这是@Taras Danylyuk的onClicked的实现,它使用setState的回调版本来避免计时问题:

onClicked(number) {
  this.setState((oldState) => {
    let clicked = Object.assign([], this.state.clicked);
    let index = clicked.indexOf(number);
    if(index !== -1) {
      clicked.splice(index, 1);
    } else {
      clicked.push(number);
    }
    return { clicked };
  });
}

The reason you need this is because you are modifying your new state based on the old state. 之所以需要这样做,是因为您正在基于旧状态修改新状态。 React doesn't guarantee your state is synchronously updated, and so you need to use a callback function to make that guarantee. React不能保证您的状态被同步更新,因此您需要使用回调函数来保证这一点。

You have onClicked() define in your 'main-content' class. 您已经在“主要内容”类中定义了onClicked()。 So that's where it fires. 这就是它触发的地方。

constructor(props) {
    // super, etc., code
    this.onClicked = this.onClicked.bind(this);    // Remove this line.
}

Remove that part. 删除该部分。

You can keep the onClicked() function where it is. 您可以将onClicked()函数保留在onClicked()处。 Your call in render() is incorrect, though: onClick = {this.onClicked}> . 但是,您在render()中的调用不正确: onClick = {this.onClicked}> That accesses the onClicked ATTRIBUTE , not the onClicked FUNCTION , it should be this.onClicked(). 访问onClicked ATTRIBUTE ,而不是onClicked FUNCTION ,应该是this.onClicked()。

Let me cleanup your call in render() a little bit: 让我稍微清理一下render()的调用:

render() {
  let tileClass = 'tile-content';
  return (
    <div className = 'main-content'>
          // some stuff
          <section
               key={item.id}
               className={tileClass}
               onClick={() => this.onClicked()}        // Don't call bind here.
          >
            <h4>{item.description}</h4>
          </section>
          // some other stuff
    </div>
  )
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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