#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
Ответ №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>
);
}