Пусть у нас есть массив объектов 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>;
}
Давайте сделаем инпуты для добавления новых элементов в наш массив.
Для начала сделаем три инпута и кнопку, по нажатию на которую будет происходить добавление:
return <div>
{result}
<br />
<input />
<input />
<input />
<button>save</button>
</div>;
В дальнейшем решении задачи мы можем пойти
двумя путями: можно для каждого инпута сделать
отдельный стейт, либо сделать один общий
стейт-объект, содержащий value
наших
инпутов.
Давайте рассмотрим оба пути по очереди.
Путь первый
Давайте каждому инпуту сделаем свой отдельный стейт:
function App() {
const [notes, setNotes] = useState(initNotes);
const [value1, setValue1] = useState('');
const [value2, setValue2] = useState('');
const [value3, setValue3] = useState('');
...
}
Добавим обработчики события onChange
:
return <div>
{result}
<br />
<input value={value1} onChange={event => setValue1(event.target.value)} />
<input value={value2} onChange={event => setValue2(event.target.value)} />
<input value={value3} onChange={event => setValue3(event.target.value)} />
<button>save</button>
</div>;
Сделаем так, чтобы по нажатию на кнопку вызывалась
функция addItem
:
return <div>
{result}
<br />
<input value={value1} onChange={event => setValue1(event.target.value)} />
<input value={value2} onChange={event => setValue2(event.target.value)} />
<input value={value3} onChange={event => setValue3(event.target.value)} />
<button onClick={addItem}>save</button>
</div>;
Данная функция должна взять значение каждого инпута из соответствующего стейта, сделать из этих значений объект с новым элементом, а затем добавить этот элемент в массив:
function addItem() {
let obj = {
prop1: value1,
prop2: value2,
prop3: value3,
};
setNotes([...notes, obj]);
}
Кроме того, добавляемый элемент должен иметь
уникальный id. Будем генерировать этот id
с помощью созданной в одном из предыдущих
уроков функции id()
:
function addItem() {
let obj = {
id: id(),
prop1: value1,
prop2: value2,
prop3: value3,
};
setNotes([...notes, obj]);
}
Соберем весь код вместе и получим решение нашей задачи:
function App() {
const [notes, setNotes] = useState(initNotes);
const [value1, setValue1] = useState('');
const [value2, setValue2] = useState('');
const [value3, setValue3] = useState('');
const result = notes.map(note => {
return <p key={note.id}>
<span>{note.prop1}</span>,
<span>{note.prop2}</span>,
<span>{note.prop3}</span>
</p>;
});
function addItem() {
let obj = {
id: id(),
prop1: value1,
prop2: value2,
prop3: value3,
};
setNotes([...notes, obj]);
}
return <div>
{result}
<br />
<input value={value1} onChange={event => setValue1(event.target.value)} />
<input value={value2} onChange={event => setValue2(event.target.value)} />
<input value={value3} onChange={event => setValue3(event.target.value)} />
<button onClick={addItem}>save</button>
</div>;
}
Возьмите таблицу с продуктами initProds
.
Сделайте под таблицей инпуты для добавления
нового продукта.
Сделайте так, чтобы текст инпутов очищался после добавления продуктов.
Путь второй
Сделаем так, чтобы значения инпутов были привязаны к одному объекту, вот такому:
const obj = {
prop1: '',
prop2: '',
prop3: ''
}
Пусть этот объект также хранит в себе id
нового элемента массива:
const obj = {
id: 'ай ди нового элемента'
prop1: '',
prop2: '',
prop3: ''
}
Сделаем специальную функцию, которая будет
возвращать нам описанный объект, сгенерировав
в нем случайный id
:
function getInitObj() {
return {
id: id(),
prop1: '',
prop2: '',
prop3: ''
}
}
Используем эту функцию для получения начального значения стейта:
function App() {
const [notes, setNotes] = useState(initNotes);
const [obj, setObj] = useState(getInitObj()); // используем функцию
...
}
Давайте привяжем части нашего объекта к инпутам:
return <div>
{result}
<br />
<input value={obj.prop1} />
<input value={obj.prop2} />
<input value={obj.prop3} />
<button>save</button>
</div>;
Привяжем в качестве обработчика onChange
инпутов общую функцию changeProp
:
return <div>
{result}
<br />
<input value={obj.prop1} onChange={event => changeProp('prop1', event)} />
<input value={obj.prop2} onChange={event => changeProp('prop2', event)} />
<input value={obj.prop3} onChange={event => changeProp('prop3', event)} />
<button>save</button>
</div>;
В функции changeProp
будем изменять
свойство, имя которого передано первым параметром:
function changeProp(prop, event) {
setObj({...obj, [prop]: event.target.value});
}
В качестве обработчика клика по кнопке привяжем
функцию addItem
:
return <div>
{result}
<br />
<input value={obj.prop1} onChange={event => changeProp('prop1', event)} />
<input value={obj.prop2} onChange={event => changeProp('prop2', event)} />
<input value={obj.prop3} onChange={event => changeProp('prop3', event)} />
<button onClick={addItem}>save</button>
</div>;
Внутри функции addItem
мы можем сразу
же добавлять наш стейт obj
в качестве
нового элемента массива:
function addItem() {
setNotes([...notes, obj]);
}
После этого следует вернуть объект в исходное
состояние, чтобы произошла очистка инпута
и сгенерировался новый id
:
function addItem() {
setNotes([...notes, obj]);
setObj(getInitObj());
}
Таким образом фактически получается, что
стейт obj
хранит заготовку нового
элемента массива с уникальным id
.
Когда заготовка становится элементом массива,
то в obj
опять записывается начальная
заготовка с новым id
. И так далее.
Давайте соберем весь наш код вместе и получим решение нашей задачи:
function getInitObj() {
return {
id: id(),
prop1: '',
prop2: '',
prop3: ''
}
}
function App() {
const [notes, setNotes] = useState(initNotes);
const [obj, setObj] = useState(getInitObj());
const result = notes.map(note => {
return <p key={note.id}>
<span>{note.prop1}</span>,
<span>{note.prop2}</span>,
<span>{note.prop3}</span>
</p>;
});
function changeProp(prop, event) {
setObj({...obj, [prop]: event.target.value});
}
function addItem() {
setNotes([...notes, obj]);
setObj(getInitObj());
}
return <div>
{result}
<br />
<input value={obj.prop1} onChange={event => changeProp('prop1', event)} />
<input value={obj.prop2} onChange={event => changeProp('prop2', event)} />
<input value={obj.prop3} onChange={event => changeProp('prop3', event)} />
<button onClick={addItem}>save</button>
</div>;
}
Возьмите таблицу с продуктами initProds
.
Сделайте под таблицей инпуты для добавления
нового продукта.