Динамическое добавление и удаление строк формы с помощью react

#javascript #reactjs

#javascript #reactjs

Вопрос:

У меня есть простая форма (созданная с использованием библиотеки Semantic ui react library), которая состоит из строки с несколькими входами, я намерен использовать форму по умолчанию только для этой единственной строки при первоначальном рендеринге, но разрешить пользователю нажать кнопку, чтобы добавить дополнительную строку, которая работает нормально. Где мне нужна помощь, так это предоставление возможности удалить строку до того, как пользователь, наконец, отправит все это.

У меня есть поле формы, хранящееся в начальной переменной вне компонента (для удобства визуализации для меня больше всего):

 const formField = (
    <div style={{ display: "flex", flexDirection: "row" }}>
        <Form.Select
            label="Exercise"
            placeholder="Select an exercise"
            options={exercises}
        />
        <Form.Input label="Sets" placeholder="Enter your sets" type="number" />
        <Form.Input label="Reps" placeholder="Enter your reps" type="number" />
    </div>
);
 

И затем я сохраняю это в исходном состоянии:

 const [formRow, setFormRow] = useState([formField]);
 

jsx состоит из кнопки, которая связывает новое поле формы (строку) с состоянием, а затем я отображаю все поля на странице, предоставляя мне дополнительные строки

 <Form>
            {formRow.map((item, i) => (
                <Form.Group inline widths="equal" key={i}>
                    {item}
                    <Icon
                        name="close"
                        onClick={() => setFormRow((cur) => cur.splice(i, 1))}
                    />
                </Form.Group>
            ))}
            <Button
                color="orange"
                content="Add an exercise"
                onClick={() => setFormRow((prev) => prev.concat([formField]))}
            />
        </Form>
 

Я добавляю значок удаления для каждой строки при отображении и отображении на странице, но я не могу заставить эту функцию работать. Я пытался просто использовать splice для удаления соответствующей строки, но это не работает … он также удаляет все строки после строки, на которую я нажимаю (не совсем уверен, почему)

Форма в основном выглядит так

Кто-нибудь знает, как я могу добавить функцию для удаления каждой строки в динамически создаваемой форме jsx?

Спасибо.

Ответ №1:

Причина ошибки кроется в вашем коде в этой строке:

 onClick={() => setFormRow((cur) => cur.splice(i, 1))}
 

возвращаемое значение SPLICE метода не является исправленным массивом, оно возвращает массив удаленных значений.

Из документов MOZILLA:

Возвращаемое значение

Массив, содержащий удаленные элементы.

Если удаляется только один элемент, возвращается массив из одного элемента.

Если элементы не удалены, возвращается пустой массив.

И вы не должны использовать SPLICE , когда хотите обновить состояние реакции, этот метод изменяет исходный массив. Используйте FILTER вместо этого.

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

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

https://codesandbox.io/s/angry-wescoff-lnj71?file=/src/App.js:265-316

Или в этом коде ниже (то же самое с указанным выше URL):

 import React, { useEffect, useState } from "react";

const App = () => {
  const [formRows, setFormRows] = useState([{ id: 1 }]);

  useEffect(() => {
    console.log("formRows: ", formRows);
  });

  return (
    <div>
      {formRows.map((row) => (
        <div>
          <input></input>
          <input></input>
          <button
            onClick={() =>
              setFormRows(formRows.filter((fr) => fr.id !== row.id))
            }
          >
            remove
          </button>
        </div>
      ))}
      <button
        onClick={() => setFormRows([...formRows, { id: formRows.length   1 }])}
      >
        add
      </button>
    </div>
  );
};

export default App;
 

Ответ №2:

Следующий код будет работать для удаления строки из вашей формы

 <Icon
    name="close"
    onClick={() => setFormRow((cur) => [...cur.slice(0, i), ...cur.slice(i 1)])}
/>
 

Кроме того, я бы предложил хранить только данные для каждой строки в вашем состоянии вместо хранения jsx.
Редактировать:
Пример удаления одного элемента из списка

 const index = 2
const list = [0, 1, 2, 3, 4, 5]
console.log(list)
const newList = [...list.slice(0, index), ...list.slice(index   1)]
console.log(newList) 

 enter code here
 

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

1. К сожалению, у него все та же проблема, с которой я уже сталкивался. Он продолжает удалять все строки, которые идут после единственной, которую я также хочу удалить.

2. Этого не произойдет. если вы посмотрите на код, я удаляю только тот, который находится в индексе i . Я также приложил пример к ответу.