Давайте теперь сделаем так, чтобы с помощью одного инпута можно было и добавлять новые элементы в массив, и редактировать существующие. Пусть изначально инпут находится в режиме добавления, а клик по абзацу переводит инпут в режим редактирования.
Если инпут в режиме добавления, то по потери фокуса в массив добавится новый элемент. А если инпут в режиме редактирования, то абзац будет редактироваться одновременно с инпутом, а по потери фокуса инпут перейдет в режим добавления.
Для решения описанной задачи есть несколько подходов.
Подход первый
Сделаем два инпута и с помощью условного рендеринга будем показывать или инпут для добавления, или инпут для редактирования.
Вот реализация описанного:
function App() {
const [notes, setNotes] = useState([1, 2, 3, 4, 5]);
const [editNum, setEditNum] = useState(null);
const [value, setValue] = useState('');
const result = notes.map((note, index) => {
return <p key={index} onClick={() => setEditNum(index)}>
{note}
</p>;
});
function changeItem(event) {
setNotes([...notes.slice(0, editNum), event.target.value,...notes.slice(editNum + 1)]);
}
function stopEdit(event) {
setEditNum(null);
}
function changeValue(event) {
setValue(event.target.value)
}
function addItem(event) {
setNotes([...notes, value]);
}
let input;
if (editNum) {
input = <input
value={notes[editNum]}
onChange={changeItem}
onBlur={stopEdit}
/>
} else {
input = <input
value={value}
onChange={changeValue}
onBlur={addItem}
/>
}
return <div>
{result}
{input}
</div>;
}
Подход второй
Совместим обе операции в одном инпуте:
function App() {
const [notes, setNotes] = useState([1, 2, 3, 4, 5]);
const [editNum, setEditNum] = useState(null);
const [value, setValue] = useState('');
const result = notes.map((note, index) => {
return <p key={index} onClick={() => startEdit(index)}>
{note}
</p>;
});
function startEdit(index) {
setEditNum(index);
setValue(notes[index]);
}
function changeHandler(event) {
setValue(event.target.value);
if (editNum) {
setNotes([...notes.slice(0, editNum), event.target.value,...notes.slice(editNum + 1)]);
}
}
function blurHandler(event) {
if (!editNum) {
setNotes([...notes, value]);
} else {
setEditNum(null);
}
setValue('');
}
return <div>
{result}
<input value={value} onChange={changeHandler} onBlur={blurHandler} />
</div>;
}
Подход третий
Сделаем так, чтобы при добавлении нового элемента он сразу появлялся в виде нового абзаца. И при наборе текста в инпуте в этом абзаце сразу набирался текст нового элемента.
Для этого при получении инпутом фокуса в режиме добавления будем сразу же добавлять новый элемент в конец массива и сразу же переходить в режим редактирования для этого элемента.
Реализуем:
function App() {
const [notes, setNotes] = useState([1, 2, 3, 4, 5]);
const [editNum, setEditNum] = useState(null);
const result = notes.map((note, index) => {
return <p key={index} onClick={() => startEdit(index)}>{note}</p>;
});
function startEdit(index) {
setEditNum(index);
}
function editItem(event) {
setNotes([...notes.slice(0, editNum), event.target.value,...notes.slice(editNum + 1)]);
}
function createItem() {
if (!editNum) {
const res = [...notes, ''];
setNotes(res);
setEditNum(res.length - 1);
}
}
function stopEdit() {
setEditNum(null);
}
return <div>
{result}
<input
value={editNum ? notes[editNum] : ''}
onChange={editItem}
onFocus={createItem}
onBlur={stopEdit}
/>
</div>;
}
Практические задачи
Дан массив:
const notes = ['a', 'b', 'c', 'd', 'e'];
Выведите элементы этого массива в виде списка
ul
. Под списком реализуйте инпут для
редактирования существующих и добавления
новых пунктов списка. Решите задачу тремя
описанными подходами.
Расскажите, какие достоинства и недостатки присутствуют в описанных подходах.