@NikolaiD

Как в state изменять объекты, вложенные в массив, при динамическом рендере дополнительных полей?

Есть компонент, в стейте которого лежит массив объектов phones, метод handleChangeTel должен записывать данные в стейт, но с ним проблема, не получается правильно сделать запись, так как количество номеров телефонов может увеличиваться динамически (метод createItem добавляет номера). Как минимум один номер должен присутствовать всегда.

state = {
    phones: [{ title: "", number: "" }],
    createItemIdx: 0,
    ...this.props.contact,
  };

  handleChangeTel = (event, index) => {
    const { name, value } = event.currentTarget;
    console.log(index);
    console.log(this.state.phones);
    console.log(event.currentTarget);

    this.setState((prevState) => ({
      phones: [{ ...prevState.phones[index], [name]: value }],
    }));
  };

  createItem = () => {
    this.setState(({ createItemIdx }) => ({
      createItemIdx: createItemIdx + 1,
    }));
  };

  render() {
    const { phones, createItemIdx } = this.state;

    return (
      <form className={style.form_contact} onSubmit={this.handleSubmit}>
        <label>
          <div>Телефон</div>
          <input
            className={style.input_contact}
            type="text"
            name="title"
            value={phones[0].title}
            // value={title}
            onChange={(event) => {
              this.handleChangeTel(event, 0);
            }}
            placeholder="Мобільний, Домашній ..."
            required
          />
          <input
            className={style.input_contact}
            type="number"
            name="number"
            value={phones[0].number}
            // value={number}
            onChange={(event) => {
              this.handleChangeTel(event, 0);
            }}
            required
          />
        </label>

        {[...Array(createItemIdx)].map(() => (
          <label>
            <div>Телефон </div>
            <input
              className={style.input_contact}
              type="text"
              name="title"
              // value={phones[1].title}
              onChange={(event) => {
                this.handleChangeTel(event, 1);
              }}
              placeholder="Мобільний, Домашній ..."
              // required
            />
            <input
              className={style.input_contact}
              type="number"
              name="number"
              // value={phones[1].number}
              onChange={(event) => {
                this.handleChangeTel(event, 1);
              }}
              // required
            />
          </label>
        ))}

        <div>
          <IconButton onClick={this.createItem}>
            <Add width="10" height="10" />
          </IconButton>
        </div>

        <button type="submit">
          {this.state.id ? "Редагувати" : "Зберегти"}
        </button>
      </form>
    );
  }
}
export default ContactForm;
  • Вопрос задан
  • 54 просмотра
Решения вопроса 1
0xD34F
@0xD34F Куратор тега React
state = {
  phones: [
    { id: 1, title: '', number: '' },
  ],
}

onChange = ({ target: { value, name, dataset: { index } } }) => {
  this.setState(({ phones }) => ({
    phones: phones.map((n, i) => +index === i
      ? { ...n, [name]: value }
      : n
    ),
  }));
}

addPhone = () => {
  this.setState(({ phones }) => ({
    phones: [
      ...phones,
      {
        id: 1 + Math.max(...phones.map(n => n.id)),
        title: '',
        number: '',
      },
    ],
  }));
}

delPhone = ({ target: { dataset: { index } } }) => {
  this.setState(({ phones }) => ({
    phones: phones.filter((n, i) => i !== +index),
  }));
}

render() {
  return (
    <div>
      {this.state.phones.map((n, i) => (
        <div key={n.id}>
          <input name="title" data-index={i} value={n.title} onChange={this.onChange} />
          <input name="number" data-index={i} value={n.number} onChange={this.onChange} />
          {i ? <button data-index={i} onClick={this.delPhone}>x</button> : null}
        </div>
      ))}
      <button onClick={this.addPhone}>Add</button>
    </div>
  );
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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