Задать вопрос
@poniatowski

Корректное удаление элемента массива через input onChange как сделать?

Хотелось бы видеть в таблице суммы при каждом отмеченном инпуте. Где ошибка? - на первый взгляд код работает, но если речь идет о последнем инпуте, то из массива он не удаляется. Подозреваю, что это связано со сплайсом.
https://codesandbox.io/s/7zqmjrnjw1
  • Вопрос задан
  • 226 просмотров
Подписаться 1 Простой Комментировать
Помогут разобраться в теме Все курсы
  • Нетология
    Frontend-разработка на React
    10 недель
    Далее
  • Академия Эдюсон
    React-разработчик + ИИ
    2 месяца
    Далее
  • Яндекс Практикум
    React-разработчик
    3 месяца
    Далее
Решения вопроса 2
0xD34F
@0xD34F Куратор тега React
this.state.deleteSum.splice(index, 1);

Что такое index? Это индекс элемента массива workers. А использовать вы его пытаетесь как индекс элемента массива deleteSum. Конечно, иногда они могут совпадать, но чаще этого не будет. Например, в deleteSum сохранено значение элемента под индексом 2, и больше ничего. Т.е., индекс этого значения внутри deleteSum будет 0. Понятно, что если удалять второй элемент из deleteSum, то в таком случае ничего удалено не будет.

То есть, надо бы вычислять индекс значения, которое предполагается удалить (не надо - он уже определён ранее, в условном операторе, где идёт сравнение с -1, так что надо вынести indexOf из if и сохранить в переменную). Но тут сама задумка с хранением значений свойств salary кривовата - что если они будут совпадать у разных элементов workers? Одно от другого нельзя будет отличить, т.е., если значение уже присутствует в deleteSum, то будет непонятно, надо его удалить или добавить ещё раз.

Правильнее было бы сохранять индексы:

const checked = [...this.state.deleteSum];
const i = checked.indexOf(index);
if (i === -1) {
  checked.push(index);
} else {
  checked.splice(i, 1);
}
this.setState({ deleteSum: checked });

Соответственно, при вычислении суммы лезем в массив с данными и достаём оттуда значение salary:

const sum = this.state.deleteSum.reduce((acc, n) => {
  return acc + this.state.workers[n].salary;
}, 0);

А вообще, есть вариант обойтись и без дополнительного массива, если сохранять состояния чекбоксов в элементы workers:

class App extends React.Component {
  state = {
    workers: [
      { name:    'mike', surname:   'nike', salary: 1000 },
      { name: 'nikolas', surname: 'reebok', salary:  250 },
      { name:    'john', surname: 'adidas', salary:  150 },
    ],
  }

  onChange = ({ target: { checked, dataset: { index } } }) => {
    this.setState(({ workers }) => ({
      workers: workers.map((n, i) => i === +index
        ? { ...n, checked }
        : n
      ),
    }));
  }

  render() {
    const { workers } = this.state;
    const sum = workers.reduce((acc, n) => acc + (n.checked ? n.salary : 0), 0);

    return (
      <React.Fragment>
        <table>
          <tbody>{workers.map((n, i) => (
            <tr>
              <td>{n.name}</td>
              <td>{n.surname}</td>
              <td align="right">
                <label>
                  {n.salary}
                  <input
                    type="checkbox"
                    data-index={i}
                    checked={n.checked}
                    onChange={this.onChange}
                  />
                </label>
              </td>
            </tr>))}
          </tbody>
        </table>
        <div>Сумма зарплат: {sum}</div>
      </React.Fragment>
    );
  }
}
Ответ написан
Комментировать
@h88p
Pre-Junior HTML Developer
this.state.deleteSum.splice(this.state.deleteSum.indexOf(checkedItem), 1);

При удалении из массива вы удаляли с index, а у цены, которую вы хотите удалить, индекс может не совпадать с this.state.deleteSum
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
rockon404
@rockon404 Куратор тега React
Frontend Developer
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы