Связываем компоненты вместе
На данный момент у нас имеются все компоненты, которые нам нужны, пришло время объединять их.
В этом уроке мы должны ответить на несколько вопросов:
Где хранить список?
Каким образом мы добавляем новые пункты?
Как отобразить несколько дел сразу?
Каким образом мы их удаляем?
В этом уроке присутствует повышенная концентрация JavaScript. Я постараюсь объяснить все сложные моменты, а глубже с теорией мы познакомимся в следующей главе.
Где хранить список?
У нас есть два компонента: первый (Field.jsx
) добавляет новые элементы, второй (Item.jsx
) отображает их и имеет возможность удалить. Так как компоненты не должны знать друг о друге, быть максимально изолированными, хранить данные мы будем в ближайшем общем предке, стало быть, TodoApp.jsx
:
Каким образом мы добавляем новые пункты?
Нам нужен способ сообщить в главный компонент (TodoApp
), что произошло нажатие кнопки добавления, и что Field
хочет добавить новую запись в наш список. В Реакте это делается с помощью коллбеков. Коллбек (от англ. call back — "перезвони мне") — это функция, которая передается из родительского компонента в дочерний как параметр, которую дочерний компонент вызывает для того, чтобы сигнализировать родителю о том, что произошло какое-то действие. Давай посмотрим, как мы можем применить это в нашей ситуации.
Для начала добавим Field
в TodoApp
(не забудь импортировать его):
Создадим функцию, которая будет коллбеком и добавим ее к пропсам Field
:
Перейдем в Field.jsx
и пропишем этот коллбек как обработчик нажатия кнопки:
(некоторые куски кода были пропущены для краткости)
Что здесь происходит:
При нажатии кнопки вызывается
onButtonClick
onButtonClick
вызывает переданный "сверху"onAdd
и передает ему как первый аргумент значение поля ввода.
Вернемся в TodoApp.jsx
и напишем код, который добавляет элемент в список:
Это сложная конструкция, давай разберем по частям:
Функция
addNewItem
вызывается, когда мы нажимаем на кнопку добавления.newItem
— новый элемент.Внутри неё мы изменяем значение
items
, теперь оно равно[...items, newItem]
[...items, newItem]
— это способ описать массив, который состоит из всех элементовitems
, а такжеnewItem
.
Как отобразить несколько элементов списка сразу
Теперь, когда у нас есть список, в который мы можем добавлять элементы, нам надо научиться их отображать. Компонент элемента списка, кстати, должен выглядеть примерно так:
Вернемся в TodoApp
. У нас есть массив items
, надо "сконвертировать" их в <Item name={...}/>
(кстати, не забудь импорировать его) и добавить в дерево. В этом нам поможет функция map
.
Представь, что у тебя есть фабрика с конвейером. Пустые бутылки проходят по конвейеру через аппарат, который наливает в них воду. На входе было 100 пустых бутылок, на выходе — 100 полных бутылок. Так вот твой массив — это бутылки на конвейере, а map — это аппарат.
map
вызывает функциюf
с каждым элементом массива, над которым она была вызвана, и составляет новый массив из результатов выполнения функции.
В нашем случае есть массив строк, нужно из него сделать массив Item
:
Теперь добавим наши элементы в компонент TodoApp
:
Проверь в браузере, что элементы добавляются.
Дополнительная информация
React устроен таким образом, что он пытается произвести как можно меньше манипуляций с веб-страницей для достижения нужного результата. Недостатком этого метода является то, что он иногда "путает" элементы массива и не всегда знает, какой элемент документа соответствует какому элементу массива.
Для этого было придумано "магическое" свойство key
. Правило простое:
Если у нас есть массив React-компонентов, то у каждого из них должен быть свой, уникальный внутри массива,
key
.
Давай разберемся, как им пользоваться.
Мы говорили о том, что map
вызывает функцию f
с каждым элементом массива. Однако, map передает в f
не один, а три аргумента:
Элемент массива
Порядковый номер (индекс) элемента
Сам массив.
Перепишем функцию createItem
так, чтобы она использовала порядковый номер в качестве key
:
Удаление элементов
В этой главе мы познакомимся с сестрой функции map
— функцией filter
.
filter
вызывает функциюf
с каждым элементом массива (а также его индексом и самим массивом), над которым она была вызвана, и составляет новый массив из тех элементов исходного массива, для которыхf
вернулаtrue
.
Пример: отфильтровать массив чисел таким образом, чтобы остались только положительные:
Мы хотим написать функцию, которая обновляет список items, удалив из него элемент с указанным индексом (removedIndex
):
Что происходит: filter
вызывает f
c элементами массива, f
в свою очередь, возвращает true
для всех элементов, кроме removedIndex
.
Мы теперь можем дать нашим Item
возможность удалять себя:
А Item может запрашивать удаление себя по нажатию кнопки:
Проверь в браузере, что элементы добавляются и удаляются.
О, одна небольшая вещь для самостоятельной работы:
Подумай, как сделать так, что поле ввода очищается после нажатия кнопки добавления.
Подумай, как сделать так, чтобы нельзя было добавить пустые строки
Ответ — в конце следующей главы.
Last updated