Эта серия статей написана на основе заметок, использованных во время семинара, организованного OKE Software Poland в Гданьске, Польша. Он не претендует на то, чтобы быть всеобъемлющим и полным учебным пособием для всех, но он будет использоваться для семинара, предназначенного для разработчиков, у которых нет опыта создания SPA с использованием React. Выкладываю сюда, так как думаю, что кому-то это может быть полезно. Пожалуйста, не стесняйтесь поправлять меня, если найдете какую-то ерунду. Также имейте в виду, что английский не является моим родным языком, поэтому простите меня за любые грамматические и лингвистические ошибки. Моя четвертая статья! Наслаждайтесь!

Кстати вот предыдущая часть:



План

Часть 4 — Работа с изображениями в Webpack, компонент HeroCard, propTypes,

Итак, я нажал другую ветку step4-assets-added . В этой ветке вы можете найти две дополнительные вещи. Во-первых, это файл data.json, в котором вы найдете данные, которые мы будем использовать для заполнения наших представлений. Позже мы попытаемся перенести его в API, чтобы показать, как на самом деле выполнять вызовы AJAX в React, но пока мы будем иметь дело с простым JSON. Для информации я получил эти данные с: http://marvel.wikia.com/wiki/Marvel_Database

который является отличным источником данных о Marvel. Во-вторых, в assets есть папки comics и portaits. Мы будем использовать их, чтобы добавить в наше приложение аватары героев, а также обложки комиксов.

Верхняя панель, Фон

Итак, хорошая новость заключается в том, что теперь мы определенно можем больше сосредоточиться на кодировании, чем на настройке проекта.

Давайте начнем с того, что наведем порядок в TopBar и Background, не так ли?

Во-первых, я вижу, что мы получаем какое-то поле по умолчанию вокруг нашего элемента body. Простое исправление, давайте перейдем к нашему index.html и просто установим для всех элементов значение по умолчанию равным 0:

Чудесно. Теперь мы хотели бы добавить наш логотип Marvel в topBar, не так ли?

Перейдем к TopBar.jsx и в строке 3 добавим:

3 import logo from '../assets/Marvel-Logo.png'

Наш Webpack не в восторге от этого, но, по крайней мере, дает нам некоторую информацию, почему:

Как мы уже говорили ранее, webpack — это загрузчик файлов, но чтобы добавить файл в пакет, он определенно должен знать, как с ним обращаться. Мы указали, как работать с файлами js/jsx. Как насчет .png, .jpg и тому подобного? Как указано в документации, нам нужно добавить загрузчик файлов:



Давайте откроем webpack.config.js и добавим еще один загрузчик для работы с файлами изображений:

Также, если мы хотим использовать file-loader, мы должны добавить его в наши devDependencies:

yarn add --dev file-loader url-loader

Ок, вроде ошибка ушла. Давайте перейдем к нашему TopBar.jsx и обновим его до:
https://gist.github.com/wojciech-bilicki/0cbb5baabe6d845c7c4746ddcd2bed18

Мы добавляем префикс public, потому что это папка, в которую мы скопируем изображение. Хорошо, теперь запустите yarn bundle, и вы увидите, что папка public обновлена ​​новым файлом [hash].png. Теперь мы можем снова запустить yarn start, чтобы убедиться, что наше изображение действительно загружается. За исключением того, что это выглядит ужасно!

Хорошо, давайте немного стилизуем это, а также добавим поиск для поиска среди наших героев:

Ну, это не обязательно должно быть идеально, так как стиль не является основным направлением этого мастер-класса.

Хорошо, давайте обработаем фон нашего приложения, изменив наш Master.jsx:

Конечно, наш образ background.png хэшируется и перемещается в общую папку только после того, как мы запустим yarn bundle. В остальном это должно помочь.

Проблема в том, что если мы сейчас нажмем ссылку «Подробности», мы больше не получим наши TopBar или Background. И мы определенно хотели бы, чтобы они были там, поскольку они должны быть общими для всех наших взглядов. К счастью, React и React Router позволяют легко достичь этого. Просто вырежьте импорт TopBar из Master и переместите его в App.jsx:

Хорошо, давайте перенесем некоторые данные в React и начнем работать над другими компонентами. Как я упоминал ранее, позже мы перейдем к извлечению данных из API, но старый добрый простой JSON будет работать заранее. Давайте загрузим наш файл JSON в приложение и отобразим его содержимое. Сначала давайте изменим загрузку данных на самый высокий компонент в нашем дереве, чтобы позже мы могли легко поделиться ими с другими компонентами:

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

Давайте также изменим Master.jsx:

Хорошо, давайте изменим его на что-то более полезное. Мы должны использовать тот факт, что JSX обрабатывает в основном все, что мы вводим в фигурные скобки, как вызов функции, чтобы сделать вывод, что отображать, поэтому, очевидно, мы можем использовать такие вещи, как итерация по массиву. Что мы хотели бы получить для начала, так это отображение имен всех героев в h4 элементах, мы можем добиться этого, отображая массив героев и возвращая h4 элементов для React для рендеринга:

Если вы не знаете, что такое карта на самом деле, это функция более высокого порядка, которая принимает другую функцию в качестве параметра для перебора массива и возврата нового массива в результате вызова этой функции для каждого отдельного элемента массива. Или просто прочитайте:



Итак, вот еще одна замечательная особенность React. Вам не нужно изучать какой-либо особый синтаксис для итерации и создания элементов. Забудьте о повторении. Вы просто вызываете старую добрую функцию JS.

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

Кажется, сейчас лучше, правда? Идея теперь состоит в том, чтобы организовать концепции. Во-первых, это идея рендеринга списка героев, а во-вторых, то, как мы представляем сам компонент героя. Кажется разумным разделить их на две части. Давайте создадим HeroCard.jsx:

https://gist.github.com/wojciech-bilicki/69aaa77c85b4038f1c01868237db27f8

Обратите внимание, что в строке 41 я использую деконструкцию объекта вместо props. По сути, я выбираю вещи из объекта реквизита, используя ключ объекта, просто чтобы позаботиться о свойствах, которые я на самом деле буду использовать. Также это исключает необходимость использования префикса props в функции рендеринга. И для Master.jsx конечно:

Теперь концепция списка и компонент, отображаемый для каждого элемента в списке, разделены! Здорово! Но знайте, что есть две проблемы. Один исходит из map итерации:

Warning: Each child in an array or iterator should have a unique "key" prop

Что это означает? Ну, React пытается быть максимально эффективным, используя свой алгоритм согласования, чтобы увидеть, какая часть деревьев изменилась и что нужно перерендерить, вместо того, чтобы просто сбрасывать все и отображать всю страницу. При добавлении или удалении элемента из списка React использует ключи для повторного использования уже обработанных элементов вместо отображения всего списка. Проверьте пример ниже:

Когда новый элемент помещается в список, React не знает, что на самом деле изменилось с тех пор, как старый элемент изменил свои индексы. React решает, что весь список должен быть перерисован.

Но если мы предоставим уникальные ключи, React узнает, что элемент с ключом cc является новым, а два других просто перемещены. Очень важно помнить, что НЕиспользуйте индексы массива, предоставляемые функцией map, в качестве ключей. Они должны быть уникальными из-за самих объектов, а не позиции в массиве. Проще говоря, не делайте:

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

Хорошо, давайте решим вторую проблему. Вы можете видеть, что в HeroCard.jsx hero подчеркнуто красным цветом с информацией:

hero is missing prop validation

Как мы знаем, JS — язык с динамической типизацией. У него есть свои минусы и плюсы конечно. Вы можете столкнуться с проблемами с instanceof, вам не хватает строгой проверки типов, и иногда вы задаетесь вопросом, является ли данная вещь строкой или числом. С другой стороны, вы можете делать действительно полезные вещи с помощью ==, также не указывая тип, что иногда позволяет вам двигаться быстрее. React не принуждает вас предоставлять типы для JS, но рекомендует использовать PropTypes. Вы можете рассматривать его как способ описания интерфейса компонента. Он сообщит вам, с каким типом реквизитов может работать этот компонент, и предупредит вас, если переданные ему реквизиты не соответствуют этому интерфейсу. Раньше этот пакет был встроен в модуль узла React, но он был перемещен в отдельный пакет, чтобы React сосредоточился только на том, чем он должен быть. Позже во время этого семинара мы перейдем к использованию Flowtype, так как он имеет очевидные преимущества перед PropTypes. PropTypes работает во время выполнения, чтобы проверять ваши типы, в то время как Flow может делать это статически. Тем не менее, сейчас я покажу, как их использовать, чтобы вы поняли, что их достаточно для безопасности типов в React. Добавим в проект PropTypes:

yarn add prop-types

И соответствующим образом обновим наш HeroCard.jsx:

Как видите, мы импортируем необходимые типы из модуля «prop-types» и указываем форму или реквизит под определением HeroCard. Мы можем решить, определяем ли мы данное свойство как обязательное или как необязательное.

Мы можем увидеть, что именно дают нам PropTypes, если мы добавим еще один propType ниже нашей формы героя, т.е.:

label: string.isRequired

И затем, если мы проверим нашу консоль:

Или если мы передаем в Master.jsx свойство label с неправильным типом:

{props.heroes.map(hero => <HeroCard hero={hero} label={Math.random()} key={hero.id} />)}

Что в итоге дает нам:

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

Это все на данный момент! Увидимся снова в следующем, где будет обсуждаться состояние компонентов :). Ваше здоровье!