Как мне вернуть входной тег из функции?

#reactjs

#reactjs

Вопрос:

У меня есть кнопка на моей веб-странице, и я хочу, чтобы входной тег появлялся всякий раз, когда пользователь нажимает эту кнопку. Ранее я пробовал что-то вроде этого:

 import React, { useState } from "react";
import "./styles.css";

export default function App() {
  const [showInput, setShowInput] = useState(false);
  const handleClick = () => setShowInput(true);
  return (
    <div className="App">
      <button onClick={handleClick}>Click me</button>
      {showInput ? <input type="text" /> : ""}
    </div>
  );
}
  

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

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

1. Вы хотите иметь возможность скрывать входной элемент?

2. скрыть? Нет? Не просматривайте мой код, я просто поместил его туда, чтобы показать вам, ребята, как я подошел к этой проблеме. Мне просто нужна кнопка, которая добавляет входной тег всякий раз, когда пользователь нажимает на него

3. О, хорошо, и я предполагаю, что вы также хотите, чтобы входные элементы были управляемыми компонентами?

4. Что вы подразумеваете под контролируемыми компонентами? @Yousaf

5. Компоненты, управляемые реакцией

Ответ №1:

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

Состояние после добавления одного ввода может выглядеть так, как показано ниже:

 { 
   input1: { value: '' }
}
  

Аналогично, по мере добавления большего количества входных данных в состояние будет добавлено больше объектов.

Это позволит вашим элементам ввода быть controlled components и позволит вам обрабатывать onChange событие только с помощью одной функции обработчика событий.

ДЕМОНСТРАЦИЯ

 let counter = 1;

function App() {
  const [inputs, setInputs] = React.useState({});

  const handleClick = () => {
    const inputName = "input"   counter  ;
    const inputObj = { value: "" };

    setInputs({ ...inputs, [inputName]: inputObj });
  };

  const handleChange = (event) => {
    const { name, value } = event.target;
    setInputs({ ...inputs, [name]: { ...inputs[name], value } });
  };

  return (
    <div className="App">
      <button onClick={handleClick}>Add Input</button>

      <div className="inputContainer">
        {Object.keys(inputs).map((inputName) => {
          const { value } = inputs[inputName];
          return (
            <input
              key={inputName}
              name={inputName}
              value={value}
              onChange={handleChange}
              placeholder={inputName}
            />
          );
        })}
      </div>
    </div>
  );
}

ReactDOM.render(<App/>, document.querySelector('#root'));  
 .App {
  font-family: sans-serif;
  text-align: center;
}

.inputContainer {
  display: flex;
  flex-direction: column;
  max-width: 300px;
  margin: 10px auto;
}

input {
  margin: 5px;
  padding: 5px;
}  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>  

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

1. Я не понял, что такое объект? как и в начале вашего ответа, вы говорите, что мы инициализируем состояние как пустой объект. Я не понял смысла этого.

2. Входные данные будут отображаться на основе пар ключ-значение в объекте, сохраненном в состоянии. Каждая пара ключ-значение в объекте представляет один элемент ввода, где имя ввода является ключом, а значение — другим объектом, который содержит данные, связанные с вводом, такие как его значение, текст-заполнитель и т.д.

3. Хорошо, но разве я не могу иметь переменную счетчика, а затем перебирать ее и печатать мой входной тег. Я имею в виду, я просто говорю. Это еще один способ решения этой проблемы. Есть ли какая-либо существенная разница между этими двумя методами? @Yousaf

4. Это приведет к отображению входных данных, но как вы получите доступ к значению каждого входного элемента? Если каждый ввод является контролируемым компонентом, то вы можете легко получить доступ к значению каждого ввода, потому что оно уже сохранено в состоянии.

5. Хорошо, я понял до метода handleClick, но что делает handleChange? Я не мог этого понять. @Yousaf

Ответ №2:

Создайте showInput число, равное значению по умолчанию 0 .

handleClick Увеличьте это число, а не просто установите true .

Вне возвращаемого выражения создайте массив. С for помощью цикла помещайте входные данные (пока не достигнете указанного числа) в массив.

Замените строку, в которой вы добавляете входные данные в JSX, этим массивом.

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

1. Обратите внимание, что для динамических массивов полезно иметь уникальные ключи, чтобы React мог правильно идентифицировать их все. Таким образом, нет проблем с их добавлением / удалением. Вы можете найти в Google информацию о массиве элементов React и уникальных ключах для получения дополнительной информации

Ответ №3:

Что-то вроде …

 import React, { useState } from "react";
import "./styles.css";

export default function App() {
  const [inputs, setInputs] = useState([]);
  const handleClick = () => setInputs([...inputs, ""]);
  return (
    <div className="App">
      <button onClick={handleClick}>Click me</button>
      {inputs.map(i => <input type="text"/>)}
    </div>
  );
}
  

Теперь вы также можете сохранить свои входные значения в своем inputs состоянии для дальнейшей обработки.

Я оставляю форматирование на ваше усмотрение … !

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

1. Если состояние ввода имеет значение по умолчанию в виде пустого массива, то какой смысл распространять его на SetInputs, а затем добавлять пустую строку? @Седрик Друк

2. Я думаю, прочитайте вопрос

Ответ №4:

 import React, { useState } from "react";

export default function App() {
  const initialValue = [{ value: "first input" }];

  const [userInputs, setUserInputs] = useState(initialValue);
  const handleClick = () => {
    const updatedInputs = [...userInputs, { value: "new input"}]
    setUserInputs(updatedInputs);
  }
  return (
    <div className="App">
      <button onClick={handleClick}>Click me</button>
      {userInputs.map((el, i) => (
        <input type="text" value={el.value} />
      ))}
    </div>
  );
}
  

Ответ №5:

Вся приведенная выше реализация верна, но у меня также есть своя собственная реализация.

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

export default function App() {
  const [showInputs, setInputs] = useState([]);

  const handleClick = () => {
    setInputs((prev) => {
      const i = prev.length   1;
      return [
        ...prev,
        <Fragment key={i}>
          <input type="text" />
          <br />
        </Fragment>
      ];
    });
  };

  return (
    <div className="App">
      <button onClick={handleClick}>Click me</button>
      <br />
      {showInputs}
    </div>
  );
}