Пусть у нас опять есть массив объектов initNotes
из предыдущего урока, элементы которого выводятся
в виде абзацев:
function App() {
const [notes, setNotes] = useState(initNotes);
const result = notes.map(note => {
return <p key={note.id}>
<span>{note.prop1}</span>,
<span>{note.prop2}</span>,
<span>{note.prop3}</span>
</p>;
});
return <div>
{result}
</div>;
}
Давайте под нашими абзацами сделаем инпуты для редактирования данных наших абзацев. Пусть в конце каждого абзаца будет кнопка для редактирования.
По нажатию на кнопку данные абзаца должны попасть в инпуты. При редактировании инпутов реактивно будет изменяться текст абзаце.
Давайте реализуем описанное.
Шаг 1
Для начала давайте сделаем стейт editId
,
хранящий в себе id
элемента, который
редактируется в настоящий момент. Если ничего
не редактируется (например, по умолчанию),
пусть этот стейт имеет значение null
:
function App() {
const [notes, setNotes] = useState(initNotes);
const [editId, setEditId] = useState(null);
...
}
Добавим теперь в конец абзаца кнопку, которая
будет записывать id
абзаца в editId
:
const result = notes.map(note => {
return <p key={note.id}>
<span>{note.prop1}</span>,
<span>{note.prop2}</span>,
<span>{note.prop3}</span>
<button onClick={() => setEditId(note.id)}>edit</button>
</p>;
});
Шаг 2
Давайте теперь сделаем так, чтобы в инпутах выводился текст редактируемого абзаца.
Для этого нам нужно из массива получить редактируемый
объект по его id
и в каждый инпут
записать соответствующее свойство этого объекта.
Пусть это значение извлекает специальная
функция getValue
:
<input value={getValue('prop1')} />
<input value={getValue('prop2')} />
<input value={getValue('prop3')} />
Давайте напишем реализацию этой функции:
function getValue(prop) {
return notes.reduce((res, note) => {
if (note.id === editId) {
return note[prop];
} else {
return res;
},
}, '');
}
Представим его в более коротком варианте:
function getValue(prop) {
return notes.reduce((res, note) => note.id === editId ? note[prop] : res, '');
}
Шаг 3
Давайте теперь сделаем так, чтобы при изменении любого инпута изменялось значение соответствующего свойства соответствующего элемента массива.
Для этого каждому инпуту в качестве обработчика
события onChange
привяжем функцию:
<input
value={getValue('prop1')}
onChange={event => changeItem('prop1', event)}
/>
<input
value={getValue('prop2')}
onChange={event => changeItem('prop2', event)}
/>
<input
value={getValue('prop3')}
onChange={event => changeItem('prop3', event)}
/>
Давайте напишем реализацию функции changeItem
:
function changeItem(prop, event) {
setNotes(notes.map(note => {
if (note.id === editId) {
return {...note, [prop]: event.target.value};
} else {
return note;
}
}));
}
Упростим код:
function changeItem(prop, event) {
setNotes(notes.map(note =>
note.id === editId ? {...note, [prop]: event.target.value} : note
));
}
Шаг 4
После инпутов сделаем кнопку, нажатие на которую будет завершать редактирование. В нашем случае это означает просто очистку инпутов.
Для этого установим стейт editId
в
null
:
<button onClick={() => setEditId(null)}>save</button>
Шаг 5
Соберем все вместе и получим решение нашей задачи:
function App() {
const [notes, setNotes] = useState(initNotes);
const [editId, setEditId] = useState(null);
const result = notes.map(note => {
return <p key={note.id}>
<span>{note.prop1}</span>,
<span>{note.prop2}</span>,
<span>{note.prop3}</span>
<button onClick={() => setEditId(note.id)}>edit</button>
</p>;
});
function getValue(prop) {
return notes.reduce((res, note) => note.id === editId ? note[prop] : res, '');
}
function changeItem(prop, event) {
setNotes(notes.map(note =>
note.id === editId ? {...note, [prop]: event.target.value} : note
));
}
return <div>
{result}
<br />
<input
value={getValue('prop1')}
onChange={event => changeItem('prop1', event)}
/>
<input
value={getValue('prop2')}
onChange={event => changeItem('prop2', event)}
/>
<input
value={getValue('prop3')}
onChange={event => changeItem('prop3', event)}
/>
<button onClick={() => setEditId(null)}>save</button>
</div>;
}
Практические задачи
Возьмите таблицу с продуктами initProds
.
Сделайте под таблицей форму для редактирования
продукта. Добавьте в таблицу еще одну колонку,
в которой будут кнопки для редактирования
продуктов.