Пусть теперь у нас дан массив объектов:
let initNotes = [
{
id: id(),
prop1: 'value11',
prop2: 'value12',
prop3: 'value13',
},
{
id: id(),
prop1: 'value21',
prop2: 'value22',
prop3: 'value23',
},
{
id: id(),
prop1: 'value31',
prop2: 'value32',
prop3: 'value33',
},
];
Давайте выведем этот массив в виде HTML таблицы, а затем сделаем так, чтобы по клику на ячейку в ней появлялся инпут для редактирования.
Переделаем массив
Для решения задачи нам нужно сделать так, чтобы для каждого значения каждого свойства можно было включать либо режим показа, либо режим редактирования.
Для этого нам придется переделать наш массив объектов в следующий:
const initNotes = [
{
id: id(),
fields: [
{name: 'prop1', value: 'value11', isEdit: false},
{name: 'prop2', value: 'value12', isEdit: false},
{name: 'prop3', value: 'value13', isEdit: false},
]
},
{
id: id(),
fields: [
{name: 'prop1', value: 'value21', isEdit: false},
{name: 'prop2', value: 'value22', isEdit: false},
{name: 'prop3', value: 'value23', isEdit: false},
]
},
{
id: id(),
fields: [
{name: 'prop1', value: 'value31', isEdit: false},
{name: 'prop2', value: 'value32', isEdit: false},
{name: 'prop3', value: 'value33', isEdit: false},
]
},
];
Решение задачи
Ниже я приведу готовое решение описанной задачи. Оно похоже на то, что мы делали в предыдущих уроках:
function App() {
const [notes, setNotes] = useState(initNotes);
const rows = notes.map(note => {
const cells = note.fields.map(field => {
let elem;
if (!field.isEdit) {
elem = <span onClick={() => startEdit(note.id, field.name)}>
{field.value}
</span>;
} else {
elem = <input
value={field.value}
onChange={(event) => changeCell(note.id, field.name, event)}
onBlur={() => endEdit(note.id, field.name)}
/>;
}
return <td key={field.name}>{elem}</td>;
});
return <tr key={note.id}>{cells}</tr>;
});
function startEdit(id, name) {
setNotes(notes.map(note => {
if (note.id === id) {
const fields = note.fields.map(field => {
if (field.name === name) {
return {...field, isEdit: true}
} else {
return field;
}
});
return {id, fields};
} else {
return note;
}
}));
}
function endEdit(id, name) {
setNotes(notes.map(note => {
if (note.id === id) {
const fields = note.fields.map(field => {
if (field.name === name) {
return {...field, isEdit: false}
} else {
return field;
}
});
return {id, fields};
} else {
return note;
}
}));
}
function changeCell(id, name, event) {
setNotes(notes.map(note => {
if (note.id === id) {
const fields = note.fields.map(field => {
if (field.name === name) {
return {...field, value: event.target.value}
} else {
return field;
}
});
return {id, fields};
} else {
return note;
}
}));
}
return <div>
<table>
<tbody>
{rows}
</tbody>
</table>
</div>;
}
Разберите код приведенного решения. Повторите его самостоятельно.
Функции startEdit
, endEdit
и changeCell
имеют практически полностью
идентичный код. Упростите их код, вынеся
общую часть в вспомогательную функцию.