открыть url внутри приложения kotlin

Веб-приложение на Kotlin + Spring Boot + Vue.js

Добрый день, дорогие обитатели Хабра!

Не так давно мне представилась возможность реализовать небольшой проект без особых требований по технической части. То есть, я был волен выбирать стек технологий на своё усмотрение. Потому не преминул возможностью как следует «пощупать» модные, молодёжные многообещающие, но малознакомые мне на практике Kotlin и Vue.js, добавив туда уже знакомый Spring Boot и примерив всё это на незамысловатое веб-приложение.

Приступив, я опрометчиво полагал, что в Интернете найдётся множество статей и руководств на эту тему. Материалов действительно достаточно, и все они хороши, но только до первого REST-контроллера. Затем начинаются трудности противоречия. А ведь даже в простом приложении хотелось бы иметь более сложную логику, чем отрисовка на странице текста, возвращаемого сервером.

Кое-как разобравшись, я решил написать собственное руководство, которое, надеюсь, будет кому-нибудь полезно.

О чём и для кого статья

Данный материал — руководство для «быстрого старта» разработки веб-приложения с бэкендом на Kotlin + Spring Boot и фронтендом на Vue.js. Сразу скажу, что я не «топлю» за них и не говорю о каких-то однозначных преимуществах данного стека. Цель данной статьи — поделиться опытом.

Материал рассчитан на разработчиков, имеющих опыт работы с Java, Spring Framework/Spring Boot, React/Angular или хотя бы чистым JavaScript. Подойдёт и тем, у кого нет такого опыта — например, начинающим программистам, но, боюсь, тогда придётся разбираться в некоторых деталях самостоятельно. Вообще, некоторые моменты этого руководства стоит рассмотреть подробнее, но, думаю, лучше сделать это в рамках других публикаций, чтобы сильно не отклоняться от темы и не делать статью громоздкой.

Быть может, кому это поможет сформировать представление о бэкенд-разработке на Kotlin без необходимости самому погружаться в данную тематику, а кому-то — сократить время работы, взяв за основу уже готовый скелет приложения.

Несмотря на описание конкретных практических шагов, в целом, на мой взгляд, статья имеет экспериментально-обзорный характер. Сейчас такой подход, да и сама постановка вопроса видится, скорее, как хипстерская затея — собрать как можно больше модных слов в одном месте. Но в будущем, возможно, и займёт свою нишу в энтерпрайзной разработке. Быть может, среди нас есть начинающие (и продолжающие) программисты, которым предстоит жить и работать во времена, когда Kotlin и Vue.js будут так же популярны и востребованы, как сейчас Java и React. Ведь Kotlin и Vue.js действительно подают большие надежды.

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

Содержание

Краткая справка

Инструменты разработки

В качестве среды разработки я бы рекомендовал использовать IntelliJ IDEA — среду разработки от JetBrains, получившую широкую популярность в Java-сообществе, поскольку она имеет удобные инструменты и фичи для работы с Kotlin вплоть для преобразования Java-кода в код на Kotlin. Однако, не стоит рассчитывать, что таким образом можно мигрировать целый проект, и всё вдруг заработает само собой.

Счастливые обладатели IntelliJ IDEA Ultimate Edition могут для удобства работы с Vue.js установить соответствующий плагин. Если же вы ищете компромисс между халявой ценой и удобством, то очень рекомендую использовать Microsoft Visual Code с плагином Vetur.

Полагаю, для многих это очевидно, но на всякий случай напомню, что для работы c Vue.js требуется менеджер пакетов npm. Инструкцию по установке Vue.js можно найти на сайте Vue CLI.

В качестве сборщика проектов на Java в данном руководстве используется Maven, в качестве сервера баз данных — PostgreSQL.

Инициализация проекта

Создадим директорию проекта, назвав, например kotlin-spring-vue. Нашем проекте будут два модуля — backend и frontend. Сначала будет собираться фронтенд. Затем, при сборке бэкенд будет копировать себе index.html, favicon.ico и все статические файлы (*.js, *.css, изображения и т.д.).

Таким образом, в корневом каталоге у нас будут находится две подпапки — /backend и /frontend. Однако, не стоит торопиться создавать их вручную.

Инициализировать модуль бэкенда можно несколькими путями:

pom.xml должен выглядеть следующим образом:

Чтобы инициализировать модуль фронтенда, переходим в корневую директорию проекта и выполняем команду:

Далее можно выбрать все настройки по умолчанию — в нашем случае этого будет достаточно.

По умолчанию модуль будет собираться в подпапку /dist, однако нам нужно видеть собранные файлы в папке /target. Для этого создадим файл vue.config.js прямо в /frontend со следующими настройками:

Поместим в модуль frontend файл pom.xml такого вида:

Важно: модули должны собираться именно в таком порядке — сначала фронтенд, потом бэкенд.

Теперь мы можем выполнить сборку проекта:

И, если всё собралось, запустить приложение:

По адресу http://localhost:8080/ будет доступна страничка Vue.js по умолчанию:

открыть url внутри приложения kotlin. image loader. открыть url внутри приложения kotlin фото. открыть url внутри приложения kotlin-image loader. картинка открыть url внутри приложения kotlin. картинка image loader.

REST API

Теперь давайте создадим какой-нибудь простенький REST-сервис. Например, «Hello, [имя_пользователя]!» (по умолчанию — World), который считает, сколько раз мы его дёрнули.
Для этого нам понадобится структура данных состоящая из числа и строки — класс, единственным назначением которого является хранение данных. Для этого в Kotlin существуют классы данных. И наш класс будет выглядеть так:

Всё. Теперь можем написать непосредственно сервис.

Примечание: для удобства будет вынесить все сервисы в отдельный маршрут /api с помощью аннотации @RequestMapping перед объявлением класса:

Обновим страничку и убедимся, что счётчик работает:

Теперь поработаем над фронтендом, чтобы красиво отрисовывать результат на странице.
Установим vue-router для того, чтобы реализовать навигацию по «страницам» (по факту — по маршрутам и компонентам, поскольку страница у нас всего одна) в нашем приложении:

Добавим router.js в /src — этот компонент будет отвечать за маршрутизацию:

Примечание: по корневому маршруту («/») нам будет доступен компонент Greeting.vue, который мы напишем чуть позже.

Сейчас же заимпортируем наш роутер. Для этого внесём изменения в

Для выполнения запросов к серверу воспользуемся HTTP-клиентом AXIOS:

Для того, чтобы не писать каждый раз одни и те же настройки (например, маршрут запросов — «/api») в каждом компоненте, я рекомендую вынести их в отельный компонент http-common.js:

Примечание: чтобы избежать предупреждений при в выводе в консоль (console.log()), я рекомендую прописать эту строку в package.json:

Теперь, наконец, создадим компонент (в /src/components)

Подключение к базе данных

Теперь давайте рассмотрим процесс взаимодействия с базой данных на примере PostgreSQL и Spring Data.

Для начала создадим тестовую табличку:

и наполним её данными:

Теперь дополним файл application.properties модуля бэкенда настройками подключения к БД:

Примечание: в таком виде первые три параметра ссылаются на переменные среды. Я настоятельно рекомендую передавать конфиденциальные параметры через переменные среды или параметры запуска. Но, если вы точно уверены, что они не попадут в руки коварных злоумышленников, то можете задать их явно.

Создадим сущность (entity-класс) для объектно-реляционного отображения:

И CRUD-репозиторий для работы с нашей таблицей:

И, наконец, обновим наш контроллер, чтобы увидеть работу с базой данных в действии:

Запустим приложение, перейдём по ссылке https://localhost:8080/api/persons, чтобы убедиться, что всё работает:

Аутентификация

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

Рассмотрим реализацию собственного сервера авторизации с использованием JWT (JSON Web Token).

Почему не Basic Authentication?

Бэкенд

Пусть в нашем приложении помимо гостей будет две группы пользователей — рядовые пользователи и администраторы. Создадим три таблицы: users — для хранения данных пользователей, roles — для хранения информации о ролях и users_roles — для связывания первых двух таблиц.

Примечание: таблицы users и roles находятся в отношении «многие-ко-многим» — у одного пользователя может быть несколько ролей (например, рядовой пользователь и администратор), и одной ролью могут быть наделены несколько пользователей.

Информация к размышлению: Существует подход, когда пользователей наделяют отдельными полномочиями (authorities), в то время как роль подразумевает группы полномочий. Подробнее о разнице между ролями и полномочиями можно прочитать здесь: Granted Authority Versus Role in Spring Security.

Создадим репозитории для работы с таблицами:

Источник

Практика по Котлину: Создание веб приложений на React и Kotlin/JS

Привет! Про Kotlin есть стереотип, будто бы это язык для разработки только под Android. На самом деле, это совсем не так: язык официально поддерживает несколько платформ (JVM, JS, Native), а также умеет работать с библиотеками для этих платформ, написанных на других языках. Такая поддержка «мультиплатформенности» позволяет не только писать всевозможные проекты на одном языке в единой форме, но и переиспользовать код при написании одного проекта под разные платформы.

В этой статье я перевожу официальный туториал Kotlin Hands-On о создании веб сайтов на Котлине. Мы рассмотрим многие аспекты программирования на Kotlin/JS и поймем, как работать не только с чистым DOM. В основном будем говорить о React JS, но также коснемся системы сборки Gradle, использования зависимостей из NPM, обращения к REST API, деплоя на Heroku, и в итоге сделаем приложение-видеоплеер.

Текст ориентирован на тех, кто немного знает Котлин и не знает или почти не знает Реакт. Если вы более опытны по этим вопросам, то части туториала могут показаться вам чрезмерно разжеванными.

открыть url внутри приложения kotlin. image loader. открыть url внутри приложения kotlin фото. открыть url внутри приложения kotlin-image loader. картинка открыть url внутри приложения kotlin. картинка image loader.

Надеюсь, статья удовлетворит пусть даже непопулярные запросы на материалы о Котлине на русском.

Предлагать правки в эту статью лучше всего на ГитХабе. Текущий перевод построен на версии оригинального туториала, актуальной на 09.04.2021.

Содержание

Шаг 1. Введение

На этой практике мы рассмотрим, как использовать Kotlin/JS вместе с популярным фреймворком React для создания красивых и поддерживаемых браузерных приложений. React позволяет создавать веб приложения современно и структурировано, фокусируясь на переиспользовании компонентов и на особом способе управления состоянием приложения. Он имеет большую экосистему материалов и компонентов, созданную сообществом.

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

Мы узнаем, как предметно-ориентированные языки (DSL) помогают выражать идеи кратким и единообразным способом без жертв читаемости, давая возможность написать полноценное приложение полностью на Котлине. Также мы покажем, как использовать уже сделанные сообществом компоненты и библиотеки, и как опубликовать получившееся приложение.

Предполагается, что у вас уже есть базовое понимание Котлина, и совсем поверхностное знание HTML и CSS. Базовое знание идей Реакта будет полезным для понимания примеров кода, но не обязательно.

Что именно мы создадим

Ежегодное событие KotlinConf стоит посетить, если вы хотите узнать больше о Котлине и пообщаться с сообществом. KotlinConf 2018 предлагал огромное количество информации в виде мастер-классов и лекций и насчитывал 1300 участников. Доклады публично доступны на YouTube, и поклонникам Котлина было бы полезно увидеть перечень докладов на одной странице и помечать их как просмотренные – идеально для погружения в Котлин «запоем». На этой практике мы как раз создадим такое приложение – KotlinConf Explorer (см. скриншот ниже).

открыть url внутри приложения kotlin. image loader. открыть url внутри приложения kotlin фото. открыть url внутри приложения kotlin-image loader. картинка открыть url внутри приложения kotlin. картинка image loader.

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

Начнем с настройки среды разработки и установки инструментов, которые помогут нам в работе.

Шаг 2. Настройка

Пререквизиты

Чтобы начать, давайте убедимся, что у вас установлена актуальная среда разработки. Вот все, что нам нужно сейчас – это IntelliJ IDEA (версии 2020.3 или новее, достаточно бесплатной Community Edition) с плагином Котлин ( 1.4.30 или новее) – скачать можно по ссылке. Выберите установочный файл, соответствующий вашей ОС (поддерживаются Windows, MacOS и Linux).

Создаем проект

Для этой практики мы подготовили стартовый шаблон проекта, включающий все настройки и зависимости.

Склонируйте этот GitHub репозиторий и откройте его с помощью IntelliJ IDEA (например, с помощью File | New | Project from Version Control. или Git | Clone. ).

Этот шаблон содержит простейший Kotlin/JS Gradle проект, на основе которого можно делать что-то свое. Так как в Gradle конфигурации шаблона уже прописаны все необходимые для практики зависимости, вам не придется изменять ее.

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

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

Зависимости и задачи Gradle

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

Блок зависимостей dependencies содержит все нужные для практики внешние библиотеки:

Если отредактировать файл, IDEA автоматически предложит импортировать изменения Gradle скриптов. Импорт также можно инициировать в любой момент, нажав на кнопку Reimport All Gradle Projects в тул-окне Gradle (сбоку справа).

HTML страница

Так как мы не можем вызывать JavaScript сам по себе, мы должны написать связанную с нашим JS файлом HTML страницу, и именно ее открывать в браузере. В проекте уже есть файл src/main/resources/index.html со следующим содержимым:

Выполняя обыденную конвенцию JavaScript, мы сначала позволяем загрузить контент нашей страницы (включая элемент #root ) и только в конце загружаем скрипт. Таким образом, страница будет загружена к моменту выполнения нашего скрипта, и мы сможем сразу же к ней обращаться.

Перед написанием «Hello, World» с настоящей разметкой, начнем с простейшего визуального примера – страницы, залитой сплошным цветом. Этот пример поможет понять, то что наш код действительно доходит до браузера и выполняется без ошибок. Для кода у нас есть файл src/main/kotlin/Main.kt с таким содержимым:

Теперь нам нужно скомпилировать и запустить наш код.

Запуск сервера для разработки

Kotlin/JS Gradle плагин из коробки поддерживает webpack-dev-server, что позволяет нам хостить приложение прямо с помощью IDE и не настраивать веб сервер отдельно.

Мы можем запустить сервер, вызвав задачу run или browserDevelopmentRun из тул-окна Gradle. Она может быть либо в группе other (как на скриншоте), либо в kotlin browser :
открыть url внутри приложения kotlin. image loader. открыть url внутри приложения kotlin фото. открыть url внутри приложения kotlin-image loader. картинка открыть url внутри приложения kotlin. картинка image loader.

Наш проект скомпилируется и забандлится, и через несколько секунд должно открыться окно браузера с пустой красной страницей, означающей, что наш код заработал успешно:
открыть url внутри приложения kotlin. image loader. открыть url внутри приложения kotlin фото. открыть url внутри приложения kotlin-image loader. картинка открыть url внутри приложения kotlin. картинка image loader.

Включение горячей перезагрузки (hot reload) a.k.a. непрерывного режима

Вместо того чтобы вручную вызывать компиляцию проекта и обновление страницы в браузере для тестирования изменений в коде, мы можем использовать режим непрерывной компиляции – Kotlin/JS поддерживает ее. Для этого нам потребуется немного модифицировать вызов run задачи Gradle.

Необходимо также убедиться, что запущенный ранее веб сервер остановлен (нажмите в IDE на красный квадрат – Stop; если работаете в терминале – нажмите Ctrl+C ).

Если вы запускаете задачу с помощью IDEA, нужно добавить флаг в конфигурацию запуска. Эту конфигурацию IDEA создала, когда мы впервые запустили Gradle задачу, а теперь нам нужно ее отредактировать:
открыть url внутри приложения kotlin. image loader. открыть url внутри приложения kotlin фото. открыть url внутри приложения kotlin-image loader. картинка открыть url внутри приложения kotlin. картинка image loader.

После применения изменений мы можем использовать зеленую кнопку Run ( |> ) для запуска сервера.

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

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

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

Примечание от переводчика насчет непрерывной компиляции

Я пробовал этот режим, и, если честно, он мне показался неудобным. Во-первых, перезагрузка страницы иногда бывает нежелательна, особенно если там были какие-то несохраненные данные. Во-вторых, я не всегда понимаю, успели ли уже перекомпилироваться код и перезагрузиться страница. В-третьих, этот режим почему-то не всегда видит изменения, и доходит до того, что приходится перезапускать Gradle задачу, то есть сама суть режима нарушается – все еще приходится делать что-то руками.

На старт, внимание.

Мы настроили пустой Kotlin/JS проект, который может развиться во все что угодно. Время начинать верстать!

Состояние проекта после выполнения этого шага доступно в ветке master в репозитории.

Шаг 3. Первая страница на Реакте – статичная

В мире программирования принято начинать обучение с Hello, World. Так давайте изменим нашу одноцветную страницу в соответствии с традициями.

Поменяйте код в файле src/main/kotlin/Main.kt на примерно следующий:

После сборки изменившегося проекта в браузере можно увидеть магию:
открыть url внутри приложения kotlin. image loader. открыть url внутри приложения kotlin фото. открыть url внутри приложения kotlin-image loader. картинка открыть url внутри приложения kotlin. картинка image loader.

Типобезопасный HTML

Библиотека kotlin-react использует котлиновскую возможность написания DSL, таким образом заменяя синтаксис разметки HTML на нечто более легкочитаемое. Возможно, такой DSL вам покажется и легче в написании.

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

О знаке + :

Проще говоря, операцию + можно понимать как инструкцию «добавь мою строчку текста внутрь этого элемента».

Переписываем классический HTML

Когда у нас есть мысли о том, как будет выглядеть наш сайт, мы можем сразу перевести наш (мысленный) набросок в котлиновское объявление HTML. Если вы уже привыкли писать обычный HTML, у вас не должно возникнуть проблем и с котлиновским. Сейчас мы хотим создать разметку, которую можно записать примерно так на чистом HTML:

Давайте переведем этот код в Kotlin DSL. Конверсия довольно прямолинейна. Если хотите поупражняться, можете попробовать переписать самостоятельно, не подглядывая в листинг ниже:

Использование котлиновских языковых конструкций в разметке

Написание HTML на DSL на самом деле имеет намного больше преимуществ по сравнению с чистым HTML. Основное отличие – это то что мы можем жонглировать контентом страницы, используя уже знакомые нам конструкции языка. Условные переходы, циклы, коллекции, подстановка внутри строк – все это будет работать в HTML DSL так же, как и обычно в Котлине.

Потом объявим два списка: для непросмотренных и просмотренных видео. Пока что можно сделать это в файле Main.kt на верхнем уровне:

Чтобы использовать эти значения в HTML, нам не нужно знать ничего, кроме базового синтаксиса Котлина! Мы можем написать код для прохода по коллекции и добавлять HTML элемент для каждого элемента коллекции. То есть вместо трех тегов p для непросмотренных видео, мы можем написать примерно такое:

Типобезопасный CSS

Библиотека kotlin-styled предоставляет чудесные типобезопасные обертки для styled-components и позволяет нам быстро и безопасно объявлять стили как глобально, так индивидуально для конкретных компонентов. Эти обертки очень похожи на концепт CSS-in-JS. Описывая стили на Котлине, мы опять же получаем возможность использовать краткие, понятные и единообразные языковые конструкции.

Нам не нужно делать дополнительных шагов для использования этого CSS DSL, так как мы уже добавили все зависимости в конфигурацию Gradle. Вот соответствующий блок:

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

Или можно воспользоваться быстрыми исправлениями с помощью Alt+Enter для добавления импортов автоматически.

Мы привели довольно минималистичный пример. Не стесняйтесь поэкспериментировать – изменять стиль приложения, как душе угодно. Можете даже поиграться с CSS Grids, чтобы сделать интерфейс отзывчивым (но эта тема уже слишком сложна для этого туториала). Попробуйте сделать шрифт (свойство fontFamily ) заголовка без засечек (значение sans-serif ), или, например, сделать гармоничные цвета (свойство color ).

Состояние проекта после выполнения этого шага доступно в ветке step-02-first-static-page в репозитории.

Шаг 4. React – о реакциях. Наш первый компонент

Основная идея

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

На самом деле, корневой элемент нашего рендеринга тоже можно представить как компонент. Если мы отметим его рамкой, то это будет выглядеть примерно так:
открыть url внутри приложения kotlin. image loader. открыть url внутри приложения kotlin фото. открыть url внутри приложения kotlin-image loader. картинка открыть url внутри приложения kotlin. картинка image loader.

А если посмотреть на структуру приложения, то можно найти следующие компоненты, каждый из которых имеет свою ответственность:
открыть url внутри приложения kotlin. image loader. открыть url внутри приложения kotlin фото. открыть url внутри приложения kotlin-image loader. картинка открыть url внутри приложения kotlin. картинка image loader.

Корневой компонент

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

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

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

Теперь часть со списками внутри App можно сделать примерно такой:

Однако здесь можно заметить проблему: App не управляет содержимым списка. Сейчас содержимое захардкожено и будет всегда одинаковое. Выходит, нам нужен механизм передачи списка внутрь компонента.

Добавляем атрибуты

В нашем случае мы хотим добавить атрибут, содержащий список докладов. Давайте переработаем наш код. Создайте следующий интерфейс в файле VideoList.kt :

Так как содержимое компонента теперь потенциально динамично (то есть переданные в рантайме атрибуты могут меняться, мы так и будем делать в следующих шагах), следует проставлять свойство key в каждый элемент списка. Он помогает Реакту понять, какие части списка нужно обновить, а какие можно оставить без изменений – хорошая и почти бесплатная оптимизация! Больше информации насчет списков и ключей можно найти, например, в официальном гайде Реакта.

Наконец, на месте использования VideoList (внутри App ) нам остается передать правильные атрибуты. Подставьте unwatchedVideos и watchedVideos примерно так:

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

Уменьшаем громоздкость вызова

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

Основной смысл такой функции – облегчение синтаксиса использования нашего компонента: теперь мы можем писать просто

Добавляем интерактивность

Теперь при клике на элементе списка в браузере мы увидим всплывающее сообщение о выбранном элементе:
открыть url внутри приложения kotlin. image loader. открыть url внутри приложения kotlin фото. открыть url внутри приложения kotlin-image loader. картинка открыть url внутри приложения kotlin. картинка image loader.

Оформлять значение onClickFunction как лямбду довольно коротко, и это удобно как минимум для прототипирования. Однако на данный момент эквивалентность ссылок на функции в Kotlin/JS работает не очень очевидно. Поэтому передача лямбды на самом деле не сильно эффективна в плане производительности. Если вам нужна максимальная эффективность, необходимо сохранять ссылки на функции в неменяющихся во время выполнения переменных и передавать в качестве значений для onClickFunction и других подобных свойств эти переменные.

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

Давайте сделаем настоящий селектор видео вместо вывода всплывающего сообщения. Будем подсвечивать выбранное видео треугольником ( |> ). Реакт нам поможет – он позволяет ввести некоторое состояние для компонента. Это будет очень похоже на добавление атрибутов – надо объявить интерфейс:

Дальше надо сделать следующее:

Когда проделаем это, мы получим такой класс:

На этом шаге у нас все, но более подробно о состоянии можно почитать в официальном React FAQ.

Состояние проекта после выполнения этого шага доступно в ветке step-03-first-component в репозитории.

Шаг 5. Работаем совместно. Композиция компонентов

Сделанные нами на предыдущем шаге пара списков сами по себе вполне работают. Однако, если мы кликнем по одному видео в каждом из списков, мы можем выбрать два видео одновременно. Это неправильно, ведь у нас только один плеер 🙂
открыть url внутри приложения kotlin. image loader. открыть url внутри приложения kotlin фото. открыть url внутри приложения kotlin-image loader. картинка открыть url внутри приложения kotlin. картинка image loader.

По-хорошему, у обоих списков должно быть единое состояние – выбранное видео, которое будет одним на все приложение. Но единое состояние не может (и не должно) храниться в разных компонентах. Принято выносить состояние наверх (как еще говорят, «поднимать» состояние).

Вынос состояния наверх

И сошлемся на него в классе App :

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

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

Передача обработчиков

К сожалению, Реакт не позволяет изменять состояние родительского компонента напрямую, как бы мы этого ни хотели. Но мы можем поступить по-другому: перенести логику обработки действия пользователя в атрибут и передавать его из родителя. Помните, что в Котлине у переменных может быть функциональный тип? Добавим еще в одно свойство в интерфейс – функцию, принимающую Video и возвращающую Unit :

И соответственно поменяем onClickFunction на вызов этой функции из атрибутов:

Теперь мы сможем передавать выбранное видео как атрибут и вынести логику выбора видео в родительский компонент, где и будем менять состояние. Иными словами, мы хотим поднять логику обработки кликов в родителя. Обновим оба места использования videoList :

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

Состояние проекта после выполнения этого шага доступно в ветке step-04-composing-components в репозитории.

Шаг 6. Больше компонентов!

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

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

Добавляем и присоединяем кнопку

Попробуем сделать кнопку-переключатель. При нажатии ее состояние, например, текст, будет изменяться в зависимости от того, просмотрено видео или нет. Для этого будем передавать еще и состояние кнопки.

Добавим еще свойств в интерфейс VideoPlayerProps :

Мы уже создали несколько компонентов, так что реализация кнопки не должна быть сложной задачей. Попробуем использовать атрибуты для изменения CSS свойств: будем раскрашивать кнопку динамически на основе состояния видео. Добавим следующий HTML DSL в метод render видеоплеера, между тегами h3 и img :

Перемещаем списки видео в состояние приложения

То есть списки могут изменяться. Давайте тогда перенесем их в состояние приложения! Опять добавим дополнительные свойства в интерфейс:

Наконец, подкорректируем вызов видеоплеера. Он будет выглядеть вот так:

Вернитесь в браузер, выберите видео, нажмите на кнопку пару раз и убедитесь, что видео перемещается между двумя списками.

Таким образом, мы реализовали основную логику нашего приложения. Будет здорово, если вы поиграетесь со стилями кнопки, и выберете тот, который вам больше всего по душе. Можете даже попробовать вынести кнопку в отдельный переиспользуемый компонент!

Время откинуться на спинку кресла и переложить тяжелую работу на других. В следующем шаге поговорим об использовании готовых и общедоступных Реакт компонентов из Котлина.

Состояние проекта после выполнения этого шага доступно в ветке step-05-more-components в репозитории.

Шаг 7. Использование NPM пакетов

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

Первая и самая очевидная недостающая функциональность – это видеоплеер.

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

Когда мы хотим использовать NPM модули из Котлина, необходимо рассказать компилятору о сигнатурах: что можно вызывать, присваивать или читать. После этого все будет статически типизировано, и IDE сможет помогать нам писать обычный код на Котлине. Объявлять декларации для каждого внешнего модуля надо в отдельном файле. Создадим файл ReactYouTube.kt со следующим содержимым:

Импорты и экспорты в JavaScript – относительно непростая тема, поэтому иногда бывает сложно найти правильную комбинацию аннотаций, чтобы компилятор Котлина импортировал все правильно. Последние две строчки в нашем случае – это эквивалент require(«react-youtube-lite»).default в JS. Они говорят компилятору: «мы уверены, что в рантайме тут получится компонент, соответствующий RClass «.

Типизированные обертки для компонента

Однако, оставив все в таком виде, мы откажемся от большого количества возможностей Котлина. Объявление dynamic типа говорит компилятору, что значение этого типа может быть любым. Компилятор не будет проверять такие объекты, а значит есть высокий риск, что что-то сломается во время исполнения (например, в проде).

К счастью, мы уже видели, как в Котлине объявляются реактовские атрибуты (как external интерфейс), а их имена мы можем найти опять же в README библиотеки. Так что на самом деле написание типобезопасных деклараций – довольно простая задача. Мы можем объявить только те свойства, которые будем использовать – в первую очередь нам будет полезно задавать ссылку на видео. Поменяем декларацию видеоплеера вот так:

Самое время заменить скучный серый прямоугольник внутри компонента VideoPlayer на только что задекларированный настоящий плеер! Удалим тег img и заменим его на следующее:

Добавляем кнопки шера

Получать удовольствие от докладов с KotlinConf лучше вместе (что является правдой и для многих других занятий). Кнопки шера – общепризнанный способ поделиться с друзьями и коллегами качественным контентом. Такие кнопки могут поддерживать, например, мессенджеры и электронную почту. Для кнопок есть уже существующие Реакт компоненты, например, из пакета react-share. Этот пакет тоже уже объявлен в конфигурации Gradle:

Теперь можно проверить, что кнопки действительно работают. Если кликнуть по ним, должно открыться окно. Если же ничего не происходит, возможно, у вас включен скрывающий такие кнопки блокировщик рекламы.
открыть url внутри приложения kotlin. image loader. открыть url внутри приложения kotlin фото. открыть url внутри приложения kotlin-image loader. картинка открыть url внутри приложения kotlin. картинка image loader.

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

Состояние проекта после выполнения этого шага доступно в ветке step-06-packages-from-npm в репозитории.

Шаг 8. Используем внешнее REST API

Вас может расстраивать, что до сих пор мы показываем только очень ограниченный захардкоженный список видео. Давайте теперь заменим эти данные реальными, получать которые мы будем из REST API.

Использование функциональности JS из Котлина

Даже без добавления библиотек браузеры дают множество возможностей. В стандартной библиотеке Kotlin/JS есть обертки как раз для этих стандартных браузерных вызовов, позволяющие делать эти вызовы комфортно и типобезопасно прямо из кода на Котлине. Мы воспользуемся обертками для Fetch API, чтобы делать HTTP запросы для обращения к REST API.

Типичный способ создавать асинхронные программы в экосистеме JavaScript – использовать колбеки. При этом приходится раз за разом дожидаться выполнения промисов, заключая функции внутрь функций, которые в свою очередь тоже могут быть заключены в других функциях. Чем сложнее код, тем тяжелее будет синтаксис из-за отступов и скобок. Код будет съезжать вправо, его будет сложнее читать и понимать весь поток выполнения, как нам, так и другим разработчикам. Несмотря на эти недостатки, в нашем случае код с колбеками может быть довольно простым:

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

Корутины вместо колбеков

Корутины и структурированная конкурентность (structured concurrency) – гигантская тема в Котлине. Если вы хотите хорошо в них разобраться, попробуйте пройти практику по корутинам. Сейчас же мы обсудим их только поверхностно. Начнем с добавления библиотеки корутин в зависимости нашего проекта.

Как и другие зависимости в нашей практики, соответствующий Gradle код уже присутствует в конфигурации еще с момента начальной настройки проекта:

Давайте теперь запросим информацию о видео, используя корутины!

Запрашиваем первое видео

Внутри App.kt или в новом файле, напишем функцию, которая будет получать видео из REST API:

С помощью быстрых исправлений импортируем нужные объекты и функции. Или добавим импорты наверху файла вручную:

Используем suspend функцию

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

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

По возвращении в браузер мы наконец должны увидеть настоящий список видео:
открыть url внутри приложения kotlin. image loader. открыть url внутри приложения kotlin фото. открыть url внутри приложения kotlin-image loader. картинка открыть url внутри приложения kotlin. картинка image loader.

На этом часть по разработке в этой практике подошла к концу. Мы прошли долгий путь, от начальной производной «Hello, World» до вполне полноценного органайзера видео.

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

Состояние проекта после выполнения этого шага доступно в ветке step-07-using-external-rest-api в репозитории.

Шаг 9. Деплоим в продакшен и в облако

После создания приложения хорошо бы его выложить для широкой общественности.

Упаковка собранного приложения

Деплоим на Heroku

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

После создания аккаунта и установки клиента и входа в него мы можем создать git репозиторий и Heroku приложение. Это делается такими командами в терминале:

В отличие от обычного JVM приложения, которое можно запустить на Heroku (например, написанное на Ktor или Spring Boot), наше приложение генерирует статичные файлы, которые надо раздавать сервером. Поэтому нужно соответствующе настроить Heroku:

Теперь можно вызвать деплой, например, такой последовательностью команд:

Если вы пушите не master ветку (а, например, ветку step* из репозитория с состоянием проекта), то нужно поменять команду, чтобы она продолжала пушить в master на Heroku (например, так: git push heroku step-08-deploying-to-production:master ).

Если все прошло по плану, вы увидите ссылку, по которой можно достучаться до нашего приложения во всемирной паутине!
открыть url внутри приложения kotlin. image loader. открыть url внутри приложения kotlin фото. открыть url внутри приложения kotlin-image loader. картинка открыть url внутри приложения kotlin. картинка image loader.

Состояние проекта после выполнения этого шага доступно в ветке final в репозитории.

Шаг 10. В дополнение: современный Реакт с хуками

Если вы прошли всю практику и хотите попробовать еще чего-нибудь крутого, в дополнение расскажем о более современных фичах Реакта.

В React 16.8 появились хуки. Они позволяют использовать состояние и другие возможности Реакта без написания классов для компонентов. Хорошая новость: котлиновские обертки Реакта поддерживают и хуки!

Чтобы понять, как устроен этот новый способ написания Реакт компонентов и как эта концепция реализована в Котлине, мы рассмотрим несколько самодостаточных примеров о двух самых используемых встроенных в Реакт хуках – state и effect. Как и другие хуки, эти два используются внутри функциональных компонентов.

Функциональные компоненты

Использовать этот компонент можно как обычно: достаточно передать его внутрь child :

Также уже знакомым вам образом можно реализовать более лаконичную обертку:

Мы проделывали аналогичное действие на шаге 4. После этого для вставки компонента на страницу достаточно написать welcome < name = "Kotlin" >.

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

Хук State

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

Есть тройка ключевых моментов, которые происходят в примере:

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

Больше о хуке State можно узнать в официальной документации.

Примечание от переводчика: в Котлине также доступна более удобная работа с useState – как с изменяемой переменной-делегатом. Тогда код упрощается, однако, становится менее похожим на традиционный Реакт:

Хук Effect

Хук эффекта приходит на помощь, когда необходимо совершить какое-нибудь побочное действие внутри компонента – такое как вызов API или установление WebSocket соединения. Для демонстрации мы реализовали следующий компонент, который запрашивает случайный факт и по приходе ответа отображает его в теге h3 :

Заметьте, что useEffect вызывается с двумя параматрами. Второй – это функция, а первый – зависимости эффекта. Зависимости определяют, какие свойства и состояния должны измениться, чтобы запустить переданную в useEffect функцию вновь. В нашем случае мы хотим сделать только один запрос к API независимо от других событий в приложении. Поэтому мы передаем пустой список в качестве зависимостей.

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

Домашнее задание

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

Шаг 11. Что дальше?

Дополнительные фичи приложения

Конечно же, сделанное нами приложение далеко не идеально. Однако этот результат вы можете использовать как стартовую точку для изучения дальнейших тем в сфере Реакта, Kotlin/JS и других близких технологий.

Поиск

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

Персистентность

Наше приложение теряет состояние просмотренного контента каждый раз при перезагрузке страницы. Возможно, настало время сделать бэк-энд. Познакомьтесь с каким-нибудь веб фреймворком, поддерживаемым Котлином (таким как Ktor), и попробуйте написать сервер для нашего приложения, который будет сохранять список просмотренных и непросмотренных видео. Или же можно обойтись без бэк-энда и сохранять информацию прямо на клиенте.

Сложные APIs

В прекрасном мире веба есть множество датасетов и APIs, с которыми можно поиграться. Почему бы не создать фотогалерею для фоток котеек? Или разукрасить свою жизнь с помощью бесплатного сервиса с разнообразными фотографиями (примечание переводчика: не забудьте обратить внимание на лицензию)? Количество данных, которые можно затащить в свое приложение, просто неисчислимо!

Стили получше: отзывчивость и сетки

На данный момент наше приложение в экстремальных ситуациях выглядит кривовато, например, в узких окнах и на экранах смартфонов. Как раз можно изучить CSS сетки (grids) и сделать приложение отзывчивым к размерам страницы (бонусная задачка: не использовать медиавыражения).

Другие библиотеки

В репозитории kotlin-wrappers можно найти больше официальных котлиновских оберток для разных JS библиотек, а также первоначальную информацию по их использованию. Например (но не ограничиваясь):

Сообщество, помощь и решение проблем

Дальнейшее изучение корутин

Мы совсем чуть-чуть потрогали мощные концепции корутин, которые стоит использовать во многих приложениях. Если вам интересно узнать больше о написании конкурентного кода, предлагаем начать с практики по корутинам.

Дальнейшее изучение Реакта

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

Возможно, в будущем вы даже станете профессионалом котлиновского Реакта!

Послесловие от переводчика

Спасибо, что дошли до конца! Если вы оценили Kotlin/JS и планируете продолжать его изучение, следующим шагом я бы порекомендовал научиться читать JS, а в особенности JSX – примеры по Реакту используют именно это, поэтому нужно понимать, как переписывать их на Котлин.

Предрекая вопросы, расскажу, почему я сам сделал выбор в пользу Kotlin DSL. В отличие от отдельно придуманного синтаксиса JSX со своими особенностями, Kotlin DSL довольно привычен и интуитивен для тех, кто уже работал с Котлином. Здесь, как говорилось, можно использовать обычные котлиновские конструкции вроде циклов, а для подключения Реакта к своему проекту достаточно подключить библиотеку – настраивать компиляцию не надо. В общем, на Котлине писать выходит более комфортно, хотя и все еще менее производительно. С нетерпением жду развития Kotlin/JS и сообщества вокруг него!

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *