Форма реакции: цикл через event.target для создания объекта

Мне нужно отправить довольно длинную форму, и я хотел бы создать объект, содержащий имя ввода в качестве ключа и значение ввода в качестве значения. Я попытался перебрать event.target и event.target.elements, как показано ниже:

handleModify(event) {
    let tempPlayer = {}
    Object.entries(event.target.elements).forEach(([name, input]) => {
        tempPlayer[name] = input;
    });
}

Но я получил TypeError о зацикливании значения циклического объекта. Вероятно, это неправильный способ зацикливания этих значений, как я увидел, выполнив вход в консоль, event.target и event.target.elements фактически содержат элементы формы html. Я не знаю, как еще получить данные формы. Моя форма выглядит так:

<form onSubmit={e=> props.onSubmit(e)}>
  <label htmlFor="name">
    Name:
    <input type="text" name="name" placeholder="Estelle Nze Minko" />
  </label>
  <label htmlFor="poste">
    Poste:
    <input type="text" name="poste" placeholder="Back" />
  </label>
  <label htmlFor="number">
    Number:
    <input type="number" min="0" max="100" step="1" name="number" placeholder="27" />
  </label>
  <label htmlFor="height">
    Height (m):
    <input type="number" min="1.00" max="2.34" step="0.01" name="height" placeholder="1.78" />
  </label>
  <label htmlFor="selects">
    Number of selects:
    <input type="number" min="0" max="300" step="1" name="selects" placeholder="88" />
  </label>
  <button type="submit">Add</button>
</form>

Я использовал этот метод, потому что именно так я делал это на стороне сервера, извлекая данные формы и зацикливая записи req.body. Однако теперь, когда я изменил шаблоны ejs на React, я не могу отправить данные формы. Вот почему я пытаюсь перебирать значения непосредственно в методе дескриптора React. Мне не удалось отправить данные формы с помощью fetch на мой сервер node + express. req.body всегда оказывалось пустым. Я думаю, это потому, что я использую body-parser и отправляю new FormData() (который не поддерживается?) как таковой:

handleModify(event) {
    event.preventDefault();
    fetch(`/players/modify/${this.props.match.params.id}/confirm`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        mode: "cors",
        body: JSON.stringify(new FormData(event.target))
    });
}

Однако, если я сначала создам объект, а затем отправлю его с помощью выборки, он сработает. Итак, кто-нибудь знает, как перебирать элементы формы или как решить проблему с выборкой? Спасибо :))


person Maëlle    schedule 03.04.2020    source источник


Ответы (3)


Это не то, как вы должны делать это в ReactJS. Вот хорошее руководство по работе с формами: https://reactjs.org/docs/forms.html

В основном вам нужно установить значение для каждого ввода и обработать соответствующий обратный вызов onChange:

e.g.

    <input type="text" name="name" value={this.state.name} onChange={onNameChange} placeholder="Estelle Nze Minko" />

Затем в вашем компоненте у вас есть метод onNameChange, который сохраняет новое значение в состояние, например:

onNameChange(event) {
  const name = event.target.value;
  this.setState(s => {...s, name});
}

Наконец, при отправке формы вам нужно использовать значения внутри this.state

handleSubmit(e) {
  e.preventDefault(); // prevent page reload
  const {name} = this.state;
  const data = JSON.stringify({name});
  fetch(`/players/modify/${this.props.match.params.id}/confirm`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    mode: "cors",
    body: data
  });
}

Это всего лишь пример, я рекомендую вам сначала прочитать ссылку, которую я вам дал.

LE: Использование неконтролируемого компонента:

https://codesandbox.io/s/dark-framework-k2zkj здесь у вас есть пример, который я создал для неконтролируемого компонента.

в основном вы можете сделать это в своей функции onSubmit:

  onSubmit(event) {
    event.preventDefault();
    const tempPlayer = new FormData(event.target);
    for (let [key, value] of tempPlayer.entries()) {
      console.log(key, value);
    }
  };
person tudor.gergely    schedule 03.04.2020
comment
Спасибо ! Я просто изменил свои компоненты, чтобы ими можно было управлять. Итак, теперь, чтобы получить объект в handleSubmit, ваш const {name} = this.state работает только для одного ввода, верно? Мне нужно было бы создать цикл данных по всем состояниям? - person Maëlle; 03.04.2020
comment
Я отредактировал свой пост и добавил неконтролируемую версию (если вы предпочитаете эту) - person tudor.gergely; 03.04.2020
comment
да, используя контролируемый компонент, вам придется сохранять каждый ввод в состояние и получать данные для отправки оттуда - person tudor.gergely; 03.04.2020
comment
Я создал следующий цикл, чтобы получить все состояния в объекте данных: Object.entries(this.state).forEach(([name, value]) => { data[name] = value; }); Однако теперь числа являются строками, знаете ли вы, как это изменить (мне нужно поставить условие для типа ввода и использовать число( ) обертка?) - person Maëlle; 03.04.2020
comment
Извините, это может быть вне контекста для этого вопроса, так что не беспокойтесь об этом! - person Maëlle; 03.04.2020

Есть ли причина, по которой вы не используете контролируемые компоненты? Вы можете оставить входные значения в состоянии, а при отправке формы просто использовать значения из состояния.

React Docs on Forms

person torquan    schedule 03.04.2020

Ошибка, кажется, возникает из-за сохранения самого input в качестве значения, возможно, вы где-то выполнили над ним операцию. Вместо этого вы можете сохранить имя и значение ввода с помощью:

tempPlayer[input.name] = input.value;

Демо:

const root = document.getElementById("root");

const { render } = ReactDOM;

function App() {
  const handleSubmit = (event) => {
    event.preventDefault();
    let tempPlayer = {}
    Object.entries(event.target.elements).forEach(([name, input]) => {
        if(input.type != 'submit') {
          tempPlayer[input.name] = input.value;
        }
    });
    console.log(tempPlayer)
  }
  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="name">
        Name:
        <input type="text" name="name" placeholder="Estelle Nze Minko" />
      </label>
      <label htmlFor="poste">
        Poste:
        <input type="text" name="poste" placeholder="Back" />
      </label>
      <label htmlFor="number">
        Number:
        <input
          type="number"
          min="0"
          max="100"
          step="1"
          name="number"
          placeholder="27"
        />
      </label>
      <label htmlFor="height">
        Height (m):
        <input
          type="number"
          min="1.00"
          max="2.34"
          step="0.01"
          name="height"
          placeholder="1.78"
        />
      </label>
      <label htmlFor="selects">
        Number of selects:
        <input
          type="number"
          min="0"
          max="300"
          step="1"
          name="selects"
          placeholder="88"
        />
      </label>
      <button type="submit">Add</button>
    </form>
  );
}

render(<App />, root);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root" />

PS: известно, что неконтролируемые формы улучшают производительность и уменьшают повторную визуализацию, как показано в форме React-ловушки. Вам не обязательно использовать контролируемый компонент.

Возможно, вам не нужны контролируемые компоненты — блог swyx

person Agney    schedule 03.04.2020
comment
Абсолютно, спасибо. Я также нашел другое решение, вызвав имя атрибута элемента в цикле for (event.target.elements[i].getAttribute("name")), но ваше решение лучше. :) - person Maëlle; 03.04.2020
comment
Значит, имя в [name, input] устарело? @Эгни - person Maëlle; 03.04.2020
comment
Хотя это правильно (не нужна контролируемая форма), я все равно не получил бы formData из event.target.elements - просто неестественно перебирать DOM в React. - person tudor.gergely; 03.04.2020
comment
@ tudor.gergely Чувство неестественности не является уважительной причиной, потому что сам React казался неестественным из-за долгого времени в других фреймворках. Ранее я ссылался на форму хука реакции, но вот использование из блога swyx - person Agney; 03.04.2020
comment
@Maëlle Я использую ввод для input.value, поэтому вам нужно деструктурировать name to something. But you could also use Object.values` для аналогичного результата. - person Agney; 03.04.2020
comment
@Agney Я полностью понимаю. Я просто думаю, что вы могли бы использовать new FormData(event.taget) вместо того, чтобы перебирать элементы, но вы можете не согласиться со мной (я действительно рад обсудить это, и мы оба чему-то учимся) - person tudor.gergely; 03.04.2020
comment
@tudor.gergely Если бы мне пришлось настроить проверку правильности полей формы, мне пришлось бы получать все поля формы, перебирая их в цикле, я не вижу, чем FormData лучше - person Agney; 03.04.2020