Редактирование элементов списка появляющимся инпутом в React

Пусть у нас есть массив:

const initNotes = [ 'note1', 'note2', 'note3', ];

Давайте выведем этот массив в виде списка ul. Затем сделаем так, чтобы по клику на любую лишку в ней появлялся инпут для редактирования ее текста.

Шаг 1

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

Сделаем это:

const initNotes = [ {text: 'note1', isEdit: false}, {text: 'note2', isEdit: false}, {text: 'note3', isEdit: false}, ];

Шаг 2

Выведем наш массив виде списка ul:

function App() { const [notes, setNotes] = useState(initNotes); const result = notes.map((note, index) => { return <li key={index}>{note.text}</li>; }); return <ul> {result} </ul>; }

Шаг 3

Сделаем так, чтобы в режиме показа показывался span с текстом, а в режиме редактирования - инпут:

const result = notes.map((note, index) => { let elem; if (!note.isEdit) { elem = <span>{note.text}</span>; } else { elem = <input value={note.text} />; } return <li key={index}>{elem}</li>; }); return <ul> {result} </ul>;

Шаг 4

По клику на span будем включать режим редактирования для данной лишки:

const result = notes.map((note, index) => { let elem; if (!note.isEdit) { elem = <span onClick={() => startEdit(index)}> {note.text} </span>; } else { elem = <input value={note.text} />; } return <li key={index}>{elem}</li>; });

Реализуем функцию startEdit:

function startEdit(index) { const copy = Object.assign([], notes); copy[index].isEdit = true; setNotes(copy); }

Шаг 5

Сделаем так, чтобы в инпут можно было вводить текст и при этом изменялся соответствующий элемент массива:

const result = notes.map((note, index) => { let elem; if (!note.isEdit) { elem = <span onClick={() => startEdit(index)}> {note.text} </span>; } else { elem = <input value={note.text} onChange={event => changeNote(index, event)} />; } return <li key={index}>{elem}</li>; });

Реализуем функцию changeNote:

function changeNote(index, event) { const copy = Object.assign([], notes); copy[index].text = event.target.value; setNotes(copy); }

Шаг 6

По потери фокуса будем отключать режим редактирования лишки:

const result = notes.map((note, index) => { let elem; if (!note.isEdit) { elem = <span onClick={() => startEdit(index)}> {note.text} </span>; } else { elem = <input value={note.text} onChange={event => changeNote(index, event)} onBlur={() => endEdit(index)} />; } return <li key={index}>{elem}</li>; });

Реализуем функцию endEdit:

function endEdit(index) { const copy = Object.assign([], notes); copy[index].isEdit = false; setNotes(copy); }

Шаг 7

Соберем все вместе и получим решение нашей задачи:

function App() { const [notes, setNotes] = useState(initNotes); function startEdit(index) { const copy = Object.assign([], notes); copy[index].isEdit = true; setNotes(copy); } function endEdit(index) { const copy = Object.assign([], notes); copy[index].isEdit = false; setNotes(copy); } function changeNote(index, event) { const copy = Object.assign([], notes); copy[index].text = event.target.value; setNotes(copy); } const result = notes.map((note, index) => { let elem; if (!note.isEdit) { elem = <span onClick={() => startEdit(index)}> {note.text} </span>; } else { elem = <input value={note.text} onChange={event => changeNote(index, event)} onBlur={() => endEdit(index)} />; } return <li key={index}>{elem}</li>; }); return <ul> {result} </ul>; }

Практические задачи

Дан массив. Выведите его в виде списка ul. В конце каждой li сделайте кнопку для редактирования. Пусть по первому нажатию на эту кнопку в тексте li появляется инпут для редактирования, а по второму нажатию - появляется измененный текст.