Вложенные циклы с дочерними компонентами в React

Перебор массивов — рабочая лошадка Javascript. Циклы могут быть мощными и забавными, а вложенные циклы тем более. Но они могут стать сложными и запутанными, когда глубоко вложены. React предлагает способ справиться с этой сложностью, помещая каждый отдельный цикл, содержащий вложенный цикл, в отдельный компонент, а затем вызывая каждый из этих компонентов из своего родителя. Недавно я прошел это упражнение, проиллюстрированное здесь.

В рамках нашего вводного учебного лагеря для разработчиков в React нам была поставлена ​​задача отформатировать множество сезонных продуктов.

Если бы мы делали это со старым добрым ванильным Javascript, мы, вероятно, использовали бы вложенный цикл, например:

for (пусть i = 0; i ‹= arr.length - 1; i++) {
document.writeln('‹h3›' + arr[i].month + '‹/h3›');
document.writeln('‹ul›')
for (пусть j=0; j ‹= arr[i].selection.length — 1; j++) {
document.writeln('‹ li›' + arr[i].selection[j] + '‹/li›');
}
document.writeln('‹/ul›')
}

январь

  • яблоки
  • Фундук
  • Груши
  • Чеснок
  • Грибы
  • Лук
  • Картофель
  • Репа

февраль

  • яблоки
  • Фундук
  • Груши
  • Чеснок
  • Грибы
  • Лук
  • Картофель

марш

  • яблоки
  • Фундук
  • Груши
  • Ревень
  • Чеснок
  • Грибы
  • Лук
  • Картофель

… и так далее

Это очень хорошо. Но мы начинаем работать с React, учимся разбивать наш проект на компоненты и перебирать массивы с помощью метода .map().

Компоненты

В дополнение к корневому компоненту, App.jsx, мой партнер и я (в нашей учебной программе мы учимся через парное программирование) создали два компонента: SeasonalProduce.jsx для хранения массива и цикла по нему, и дочерний компонент, Produce .jsx для отображения каждого элемента массива.

Первый цикл

Принимая по одной вещи за раз, мы начали с возвращения месяцев.

У нас была идея, как мы хотим, чтобы HTML отображался в компоненте Produce.

У нас хорошее начало. Мы получили именно то, что и ожидали: список месяцев.

Нашей следующей задачей было вернуть список продуктов по каждому месяцу. Мы начали с добавления «выборки» вместе с «месяцем».

Мы получили продукты в порядке, но не совсем так, как мы хотели. Нам нужен был маркированный список фруктов и овощей под каждым месяцем. Нам нужно было перебрать массив «выбор» под каждым месяцем, чтобы создать элементы маркированного списка.

Второй цикл

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

Мы получаем нашу продукцию как элементы списка под каждым месяцем, но как элементы списка второго уровня для одного элемента списка первого уровня. Что происходит?

Давайте взглянем на элементы инструментов разработчика, чтобы увидеть, какой именно HTML-код создается.

Боже мой, сколько вложенных тегов. Почему каждый кусок продукта находится внутри отдельного ‹ul› и откуда берутся эти пустые теги ‹h3›?

Код делает только то, что мы ему говорим, и в этом проблема. Давайте посмотрим, как мы сказали ему отрисовываться.

Когда мы сопоставляем полный массив, мы переходим к компоненту Produce для его рендеринга. Запуская внешний цикл для каждого месяца, он открывает ‹div›, выводит месяц в теге ‹h3›, открывает ul›, затем открывает li› для выбора. Затем начинается внутренний цикл для выбора с использованием того же блока кода в компоненте Produce для рендеринга: для каждого элемента выбора откройте div, выведите пустой ‹h3›, потому что нет «месяца». в 'выборке' откройте ‹ul›, откройте ‹li›, чтобы наконец напечатать один элемент в массиве, затем закройте все теги в обратном порядке и повторите для следующего элемента в массиве. Какая трата. Там должен быть лучший способ.

Дочерние компоненты… с циклами

Изучая React, я пришел к пониманию, что компонент React должен, насколько это возможно, делать только одну вещь. Мы создали отдельный компонент для рендеринга месяцев, названный Month, как дочерний компонент Seasonal Produce, и в значительной степени скопировали код, который у нас был в компоненте Produce.

Давайте посмотрим, что происходит в компоненте Month. Мы сделали компонент Produce дочерним элементом Month, а не Seasonal Produce. Вы могли бы сказать, что компонент Produce вложен в компонент Month (но вы, вероятно, этого не сделаете, поскольку мы не говорим об иерархии компонентов React таким образом).

Это даст нам наш месячный список, но как насчет нашего списка продуктов в каждом месяце? Мы визуализируем HTML для выбора продуктов, но там, где ранее у нас был ‹li›{props.selection}‹/li›, мы собираемся сопоставить этот массив внутри тега ‹ul›.

Мы удалили ненужный код из компонента Produce, и теперь он выглядит так.

Теперь наш вывод выглядит так. Каждый фрукт и овощ является правильным пунктом списка.

Как визуализированный код выглядит в элементах средств разработки? Все еще немного шатко со всеми этими дополнительными тегами ‹div›.

Одной из первых вещей, которые мы узнали о компонентах React, было обертывание всего в ‹div›. Мы не были уверены, что сможем безопасно удалить ‹div›. Будет ли он отображаться без ошибок?

Оказывается, мы могли удалить его. Тег ‹li› допустим в качестве тега для переноса кода в React. Теперь это правильно отформатированный HTML.

Вывод: компоненты гнезда, а не циклы

Вместо того, чтобы пытаться отформатировать вложенный цикл и получить правильный HTML, поместите внешний цикл в родительский компонент, а внутренний цикл в дочерний компонент. Иерархия компонентов родитель-потомок позаботится о вложенности циклов.

Большое спасибо моему партнеру по программированию Нелии, нашему однокурснику Крису, который помог нам с вложенным циклом, и нашему учителю Бену, который научил нас вкладывать наши циклы с дочерними компонентами.