React JS отрисовка элементов
Мне нужно реализовать форму с возможностью динамического добавления и удаления полей. Например: нажимаем на кнопку добавить новый курс и у нас появляется блок: Список участников и одно поле для ввода имени участника, а напротив него - кнопка "Добавить новое поле" при нажатии на которое должно создаваться новое поле в этом блоке (чтобы можно было добавить имя ещё одного участника). Если вдруг мы создали лишнее поле, то при нажатии на кнопку "Удалить это поле", оно должно удаляться (и только оно). Как реализовать на Vanilla JS я знаю, но при попытке перенести это на React ничего не работает.
Укажите список участников:
-------------
| | Добавить новое поле
-------------
-------------
| | Удалить это поле
-------------
Что пробовал сделать?
// App.jsx
function App() {
const [items, setItems] = useState([])
const itemsRef = useRef()
const handleAddItem = () => {
itemsRef.current.insertAdjacentHTML('beforeend', <AddItem onRemove={e => e.target.remove()} />)
}
return (
<div>
<div className="items"></div>
<button onClick={handleAddItem}>Добавить новое поле</button>
</div>
)
}
// AddItem.jsx
function AddItem({ onRemove }) {
return (
<div className="textField">
<input type="text" />
<a href="#" onClick={onRemove}>Удалить поле</a>
</diV>
)
}
Так же пробовал использовать функцию renderToString из react-dom/server, чтобы преобразовать компонент в HTML, так как код выше возвращает object Object, но теперь не срабатывает onRemove, т.к. это уже не компонент React, а HTML строка.
Пробовал так же добавлять это, как объект в массив, потом выводить через map и удалять через filter, но там начинается такая магия, что от этого решения я моментально отказался.
Ответы (1 шт):
Если для добавления участников, то в упрощенном виде вот так:
- Создать состояние с массивом всех участников,
- По клику на кнопку добавлять нового в массив,
- По кнопке удаления - фильтром удалять по
id
. - При изменении инпута в обработчике по id добавлять значение.
А если нужно обработать - манипулировать с состоянием, отфильтровать пустые и переслать дальше.
Обратить внимание на уникальный id
- в примере использовался timestamp, но лучше что-нибудь для генерации уникального подключать отдельно.
function App() {
const [users, addUsers] = React.useState([])
const handleUser = () => {
addUsers([...users, {id: +new Date(), name: ''} ])
}
const handleDelete = (currentId) => {
addUsers( users.filter( ({id}) => id !== currentId))
}
const handleChange = (currentId) => {
}
return (
<div className='App'>
<button onClick={handleUser}>Добавить участника</button>
{users.map( ({id, name}) => (
<div key={id}>
<input type="text" value={name} name="users[]" data-id={id} onChange={() => handleChange(id)} />
<button onClick={() => handleDelete(id)}>x</button>
</div>
))}
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<App />
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>