Событие ‘onClick’ влияет на состояние всех компонентов, а не только одного

#reactjs

#reactjs

Вопрос:

Я пытаюсь создать интерактивную сетку, которая при нажатии на ячейку увеличивает число только в этой конкретной ячейке. Вместо этого, когда я нажимаю на ячейку, увеличивается вся сетка, а не одна ячейка.

Я заставил React распечатать идентификатор кнопки, на которую был нажат. Он выводит только один (правильный) идентификатор. Я убедился, что передал функцию () => {} вместо ее прямого вызова. Попытка удалить функцию arrow приводит к тому, что React жалуется на это this is undefined .

Я знаю, что это может быть не лучшим способом (кого я обманываю, это самый ужасный способ) создания интерактивной сетки, но, пожалуйста, потерпите меня:

   handleCellClick(id) {
    let cells = this.state.cells.slice()
    cells[id].level = cells[id].level   1 // Increment ONLY ONE CELL
    console.log(cells[id]) // Logging to console only outputs one id, but it changes all of them?
    this.setState({ cells: cells });
  }

  render() {
    return (
      <div className="board">
        {
          Array(resolution).fill(null).map((_, x) => { // Represents the rows
            return (
              <div className='cellRow' key={x}>
                {
                  Array(resolution).fill(null).map((_, y) => { // Represents the columns
                    let id = (x * resolution)   y
                    return (
                      <Cell
                        key={id}
                        onClick={() => { this.handleCellClick(id) }} // This is where it binds the click event
                        data={this.state.cells[id]}
                      />
                    )
                  })
                }
              </div>
            )
          })
        }
        <p> {this.state.debug} </p>
      </div>
    )
  }
  

Я ожидал, что при нажатии на одну ячейку, согласно приведенному выше коду, только эта ячейка должна увеличиваться, но вместо этого, при фактическом ее тестировании, она увеличивает все ячейки.

Массив, похоже, собран правильно.

Подключение к React DevTools показывает, что каждая ячейка имеет свой элемент в массиве.

Вот функция конструктора.

 class Board extends React.Component {
  constructor(props) {
    super(props);
    this.handleCellClick = this.handleCellClick.bind(this);
    this.state = {
      cells: Array(resolution * resolution).fill({
        level: 0,
        owner: null,
      }), // 5x5 for 25 in total
      turn: 'red'
    }
  }
  

Комментарии:

1. Похоже, что при настройке вашего состояния вы присваиваете новое значение переменной всего массива, а не определенному элементу в массиве.

2. Почему вы пытаетесь использовать this функцию со стрелкой?

3. Использование этого в функции со стрелкой будет ссылаться на правильную область здесь, потому что стрелки не создают контекст. Поэтому оно будет ссылаться на область видимости класса и правильно ссылаться на методы.

4. Я основал это на вводном руководстве по реагированию reactjs.org . Он использует this функции со стрелками, поэтому я подумал, что это нормально.

5. @VladzislauUlasenka, console.log(cells[0] === cells[1] ? "What?" : "Nope :("); выводит What? , что означает, что все элементы в массиве фактически ссылаются только на один объект… так вот в чем причина: (

Ответ №1:

Вы заполняете свой state.cells одним и тем же объектом, поэтому при изменении идентификатора одного объекта cell он запускает другие. Можете ли вы изменить свой конструктор, как показано ниже, и попробовать

 class Board extends React.Component {
   const cell = {
     level: 0,
     owner: null,
     turn: 'red'
   };
  constructor(props) {
    super(props);
    this.handleCellClick = this.handleCellClick.bind(this);
    this.state = {
      cells: Array(resolution * resolution).fill(Object.create(cell))
  }