В этом руководстве я подробно расскажу об использовании React и TypeScript для создания клиентских веб-приложений. Вместе мы создадим простое приложение «Погода», которое позволит вам искать места и отображать текущую погоду и 24-часовой прогноз.

Попутно вы узнаете:

  • Загрузка приложения с create-react-app
  • Использование React с TypeScript
  • Реагировать на хуки
  • Асинхронная связь с API Open Weather
  • Базовый стиль

Вы можете найти код здесь, на GitHub. Учебник разбит на 6 шагов, разбросанных по 2 сообщениям в блоге, а репозиторий кода содержит конечный результат каждого шага в отдельной папке для удобства сравнения. Часть 2 доступна здесь.

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

Требования

  • NodeJS
  • Редактор
  • Базовое знакомство с использованием терминала

Шаг 1. Загрузите приложение с помощью create-react-app

create-react-app - это инструмент для создания проекта React, который скрывает большую часть сложности современных систем сборки JS / TS. Эта следующая команда создаст новую папку для нашего проекта, поэтому запустите ее в том месте, где вы хотите разместить проект. Поскольку мы собираемся использовать TypeScript, мы можем указать этот шаблон:

npx create-react-app weather-app --template typescript

cd weather-app

Это создаст папку проекта и выполнит npm install (или yarn, если обнаружит, что он установлен).

Внутри package.json

Заглянув внутрь package.json, вы заметите, что у проекта есть только несколько зависимостей, а также несколько полезных сценариев для запуска, сборки и тестирования проекта. Сценарии используют react-scripts, который разработан, чтобы скрыть сложность того, что на самом деле происходит под капотом.

На самом деле у нас есть сотни зависимостей, и система сборки очень сложна, но все это скрыто за react-scripts. Мы можем запустить сервер разработки, запустив:

npm start

Это должно открыть браузер и начать показывать ваше приложение, работающее на http://locahost:3000:

Важные файлы и папки

  • package.json - Определение наших зависимостей и скриптов сборки.
  • tsconfig.json - Настройки и конфигурация компилятора TypeScript.
  • public - содержит любые статические ресурсы, такие как изображения, значки и т. Д. Он также включает первую страницу, index.html.
  • public/index.html - точка входа HTML или начальная страница для вашего приложения.
  • src/index.tsx - точка входа для нашего исполняемого кода.

Обратите внимание, что с помощью React мы определяем содержимое нашей страницы в коде, и фреймворк будет обрабатывать отрисовку. Поэтому при обычных обстоятельствах нам не нужно изменять файл index.html. Во время сборки в этот файл добавляются строки импорта сценария, и это текущий код, который обновляет представление в памяти. index.tsx - это то место, где мы запускаем процесс рендеринга React для нашего приложения.

В исходном коде рендеринга используется компонент по умолчанию App из App.tsx.

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

Представление написано с использованием JSX (отсюда расширение tsx, а не ts). JSX - это расширение синтаксиса для JavaScript / TypeScript, которое позволяет писать HTML-теги прямо в коде. Это тривиально преобразуется в создание объектов во время сборки, и вы можете использовать их везде, где требуется выражение (присваивания, возврат, вызовы функций и т. Д.). Вы можете создавать объекты напрямую, но JSX более аккуратный и интуитивно понятный для построения вложенных структур представления.

Между HTML и JSX есть некоторые различия, поэтому мы не получаем конфликтов с обычным кодом JS / TS при его переводе. Например, атрибут class называется className, и мы используем верблюжий футляр, а не футляр для кебаба.

Если функция начинается с заглавной буквы (регистр Паскаля), вы можете использовать ее как компонент / тег в другом JSX, например, в index.tsx:

Вы также заметите, что мы импортируем файл CSS и изображение SVG прямо в код. Это не стандартный JS / TS, но react-scripts использует плагины Webpack, которые это поддерживают.

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

  1. Удалите содержимое App.css и index.css
  2. Удалите импорт logo.svg из App.tsx
  3. Удалить App.test.tsx и logo.svg
  4. Замените определение функции (компонента) приложения на:

Если все сработало, при сохранении браузер автоматически обновится и покажет:

Шаг 2 - Покажите таблицу местоположений

Давайте добавим поле ввода, в котором пользователь может искать местоположение, и добавить это местоположение в таблицу. Для начала, местоположение будет строкой, а список всех местоположений в таблице будет массивом строк.

Создайте представление, заменив компонент приложения на:

Как видите, это просто построение представления так же, как и в случае с HTML. При сохранении приложение должно выглядеть так:

Обратите внимание, однако, что ввод текста в поле ввода не работает. Это связано с тем, что мы указали значение бокса как постоянную строку «Paris», а React контролирует рендеринг представления, включая его содержимое.

Представляем государство

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

Мы вводим состояние в функциональные компоненты с помощью хука useState. Посмотрите великолепное вступление Росс Дженкинс к React Hooks. Хуки должны идти в начале функции, а ловушка useState возвращает кортеж, содержащий текущее значение состояния, и функцию для обновления состояния, которую мы можем деструктурировать в одной строке:

'Paris' - начальное значение, и типы предполагаются. Нет никаких идентификаторов или имен для идентификации определенных частей состояния, постоянный порядок вызовов - это то, как состояние идентифицируется. Вот почему хуки идут в начале функции и не могут быть внутри какого-либо потока управления, такого как if.

Затем нам нужно включить значение locationSearch в наш JSX. Мы можем встраивать выражения в JSX, используя {}:

Обратите внимание, что при присвоении атрибута значения кавычки не используются. При присвоении атрибутов выражениям в React мы всегда используем attribute={expression}, а не attribute="{expression}".

Наконец, нам нужно добавить обработчик onChange (обратите внимание на случай верблюда) для вызова функции setLocationSearch при изменении элемента управления. Опять же, мы используем {} для предоставления выражения функции стрелки:

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

Отображение строк в таблице

Давайте продолжим и добавим некоторое состояние для строк таблицы.

Чтобы отобразить это в представлении, нам нужно иметь строку tr для каждой записи в массиве, поэтому мы буквально делаем map:

Обратите внимание, как внутри map стрелочной функции мы можем вернуть вложенный JSX, а JSX, в свою очередь, может встроить вложенное {} выражение.

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

Если все сработало, тогда представление должно выглядеть так, как если бы оно было со статическим содержимым:

Добавление местоположения

Для поддержки добавления местоположения нам нужно запускать действие при нажатии кнопки поиска. Это похоже на обработчик input, но вместо события onChange мы теперь обрабатываем событие onClick. Обратите внимание, что мы модифицируем массив местоположений, устанавливая совершенно новое значение состояния, а не изменяя его. Это легко сделать с помощью оператора спреда. Мы также используем locationSearch в качестве данных для добавления, НЕ элемент управления input. В React состояние - это источник истины.

Давайте еще немного поправим код:

  • Выделите обработчика как местного const
  • Отключите кнопку, если locationSearch пусто
  • Сделайте поисковый текст пустым после поиска

Дальнейшая уборка

Мы можем удалить исходные фиктивные данные из наших useState ловушек.

Обратите внимание, что для состояния locations тип исходных данных, пустой массив, не может быть выведен, поэтому мы явно указываем общий параметр string[]. Для locationSearch он автоматически определяется как string.

Давайте также добавим Bootstrap для базового стиля. Сначала добавляем пакет в наш проект,

npm install --save bootstrap

Затем импортируйте CSS - мы можем сделать это прямо в коде в index.tsx, поскольку react-scripts поддерживает это.

Теперь мы можем использовать классы Bootstrap в наших элементах пользовательского интерфейса. Обратите внимание на использование className вместо class.

Приложение сразу выглядит лучше.

Шаг 3: разделение компонентов

В настоящее время в нашем приложении есть только один компонент App. Давайте разберем поиск и таблицу на отдельные компоненты. Это обычная практика для создания больших пользовательских интерфейсов, где мы структурируем приложение в виде дерева компонентов:

Компонент поиска местоположения

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

Начнем с LocationSearch компонента, создав файл с именем LocationSearch.tsx и поместив в него следующий код:

Здесь я в основном вырезал и вставил эту поисковую часть представления из файла App.tsx. Я добавил тип FC к функции стрелки, чтобы строго ввести мое определение - это тип React, определяющий функциональный компонент.

Обратите внимание, что я также импортировал React в первой строке. До React 17 эта строка требовалась во всех файлах, использующих JSX. Это связано с тем, что теги в конечном итоге были преобразованы в вызовы React.createElement. В React 17 это преобразование было изменено, и этот импорт не требуется.

Затем я должен подумать о своем состоянии - должно ли состояние строки locationSearch принадлежать App или LocationSearch? В этом случае вводимый текст временный, и я рад переместить его в этот новый компонент.

Однако обработчик onClick изменяет состояние locations. Я не хочу, чтобы состояние locations в этом элементе управления, так как другие части моего приложения тоже будут его использовать, поэтому я оставлю это состояние в App. При каждом нажатии кнопки поиска мне приходится связываться от этого дочернего компонента с App - мы делаем это, определяя обратный вызов prop.

Добавление реквизита к компонентам

Опора - это вход для компонента, указанного в качестве атрибута в JSX. Например:

Все свойства сгруппированы в объект, который передается нашему функциональному компоненту в качестве параметра. Мы можем думать о состоянии как о принадлежащем компоненту, и это чтение и запись. Свойства доступны только для чтения и не принадлежат компоненту, они передаются. Передавая функции в качестве свойств обратного вызова, мы можем присоединять обработчики событий - в данном случае обработчик для onSearch.

В TypeScript мы создаем интерфейс для всех свойств и указываем его как общий параметр FC:

Обратите внимание, что обратный вызов принимает строку, а не параметр MouseEvent щелчка. Это еще одна полезная вещь, связанная с наличием компонентов, мы можем скрыть детали низкого уровня и создать более понятные интерфейсы.

Если указать общий параметр в FC, параметр функции props будет набран правильно. Мы можем напрямую деструктурировать в списке параметров и использовать onSearch.

Теперь, когда у нас есть функция обратного вызова, входящая в наш компонент, мы можем вызывать ее при нажатии кнопки поиска.

Наконец, мы можем обновить App.tsx, чтобы использовать этот новый компонент:

Компонент таблицы местоположений

Для табличного компонента это аналогичный процесс.

  • Создайте файл с именем LocationTable.tsx
  • Переместите представление таблицы из App.tsx в новый компонент в файле
  • Добавьте интерфейс для реквизита - в данном случае локации для отображения

Затем App.tsx можно обновить, чтобы использовать этот новый компонент:

Следующие шаги

На данный момент мы многого достигли,

  • Загрузил проект React с нуля
  • Изучил основы React - компоненты, состояние и свойства, значения привязки, базовые хуки, добавление обработчиков событий.
  • Используемый TypeScript для безопасности

В Части 2 мы будем развивать это, чтобы:

  • Интегрируйте реальный погодный сервис
  • Используйте асинхронную связь
  • Применить больше крючков

Так что обязательно вернитесь и посмотрите Часть 2. Вы также можете узнать, что мы рассматриваем в нашем полном курсе React.

Первоначально размещено здесь.