От разработчика Angular

Что происходит, когда преданный своему делу разработчик Angular переходит и экспериментирует с React, работая над приложением Ionic? Получится ли это хорошо или приведет к катастрофе?

Так случилось, что именно это я и сделал в новогодние каникулы. Меня попросили придумать несколько примеров вопросов, чтобы проверить чье-то знание Ionic. «Angular или React?» Я спросил. — Как насчет обоих? был ответ.

Поэтому я решил создать несколько вопросов Ionic, основываясь на некоторых реальных проблемах, с которыми я столкнулся, создав примеры как для Angular, так и для React. Это означало изучение хотя бы части Ionic-React. В этом посте собраны некоторые вещи, которые меня приятно удивили.

Фон

Сначала немного предыстории. Все, кто знаком со мной или с тем, что я пишу, знают, что я большой поклонник Ionic Framework. Я открыл для себя Ionic еще во времена его v0.5, когда я хотел создать мобильное приложение с Cordova, но также использовать AngularJS. Когда Ionic вступил в подростковый период с версией 2, он превратился из JavaScript и AngularJS в Angular 2 и TypeScript. Эта зрелость продолжилась в юношеской взрослой жизни с версией 3, но по мере приближения взрослой жизни вырисовывались большие вещи.

Фреймворк-агностик

Ionic версии 4 официально представила полностью переписанные компоненты. Они были реализованы как веб-компоненты, не зависящие от фреймворка, и написаны на собственном недавно созданном компиляторе Ionic Stencil.

Не вдаваясь в подробности, Stencil позволил Ionic создать всю свою библиотеку компонентов таким образом, чтобы их можно было использовать повторно, независимо от фреймворка, выбранного разработчиком Ionic. Фактически, начиная с версии 4, компоненты Ionic можно было использовать вообще без фреймворка! Это была огромная веха, и в конечном итоге она привела к созданию библиотеки Ionic-React (а вскоре и библиотеки Ionic-Vue).

Эксперимент

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

Проекты

Я создал два идентичных проекта на основе шаблона бокового меню Ionic, один с Ionic-Angular, а другой с Ionic-React, используя следующие команды:

ionic start "SampleAngularApp" sidemenu --type=angular
ionic start "SampleReactApp" sidemenu --type=react

Добавьте страницу «Помощь»

Затем мне нужна была пустая страница, на которую я мог бы быстро перетаскивать компоненты. «Просто, — подумал я. Мне просто нужно запустить ionic generate в каждом проекте и создать страницу «помощи».

Ионно-угловой

Внутри каталога проекта Ionic-Angular я выполнил следующую команду:

ionic generate page help
CREATE src/app/help/help-routing.module.ts (339 bytes)
CREATE src/app/help/help.module.ts (458 bytes)
CREATE src/app/help/help.page.scss (0 bytes)
CREATE src/app/help/help.page.html (123 bytes)
CREATE src/app/help/help.page.spec.ts (633 bytes)
CREATE src/app/help/help.page.ts (248 bytes)
UPDATE src/app/app-routing.module.ts (1954 bytes)

Это больше, чем мне нужно, но сойдет.

Ионная реакция

Затем я запустил ту же команду из каталога проекта Ionic-React:

ionic generate page help
[ERROR] Cannot perform generate for React projects.
        
Since you're using the React project type, this command won't work. The
Ionic CLI doesn't know how to generate framework components for React
projects.

Что ж, к сожалению.

Я знаю, что Ionic CLI делегирует большую часть своей работы Angular CLI за кулисами, но я предполагал, что у него будет некоторая поддержка поддержки React. Это не. Я провел большую часть следующего часа, пытаясь выяснить, какую команду React CLI использовать для формирования новой страницы, только чтобы обнаружить, что ее не существует. На самом деле, кажется, что нет стандартного способа сделать это. Мой уровень самодовольства Angular немного увеличился.

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

Тот факт, что страница представляет собой один файл .tsx, а не папку из 4–6 файлов, не ускользнул от меня. Я оценил этот уровень простоты, хотя должен отметить, что он не содержит никакой информации о маршрутах, модульных тестов или определений модулей. Помимо модульных тестов, я не скучаю по этому уровню сложности.

Интеллисенс!

Первое, что я решил добавить, была простая кнопка. Я хотел создать кнопку шириной блока в нижнем колонтитуле страницы с надписью «Click Me». Будучи более знакомым с Ionic-Angular, я сначала реализовал его там.

<ion-footer>
  <ion-toolbar>
    <ion-button expand="block" size="large" color="dark">
      Click Me!
    </ion-button>
  </ion-toolbar>
</ion-footer>

Однако, открыв мою страницу Ionic-React, я столкнулся с небольшим камнем преткновения. Ни одно из имен тегов не совпадает. Ему не понравилось, когда я просто скопировал и вставил приведенный выше код на свою страницу React.

Именно тогда я заметил, что существующие HTML-компоненты на странице React были похожи на компоненты Angular, но все они были написаны в PascalCase (иногда ошибочно называемом CamelCase), а не в kebob-case. Это заставило меня предположить, что у меня были правильные компоненты, но неправильный корпус.

Поэтому я добавил новую строку сразу после закрывающего тега </IonContent>. Я начал создавать футер, набрав <IonFo, и редактор кода предложил мне дополнить тег как <IonFooter></IonFooter>! Что это за черная магия вуду? Intellisense (завершение кода) в разметке моей страницы Ionic? Если не считать некоторых фрагментов кода, специфичных для Ionic, это было для меня новым*.

Следующий приятный сюрприз случился через несколько секунд, когда я запустил компонент <IonButton>. Мало того, что IDE предоставила мне открывающие и закрывающие теги, представьте себе мою радость, когда я получил раскрывающийся список всех атрибутов тега и их документацию.

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

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

Декларативный и императивный

Одной из проблем, с которой я столкнулся, когда обновлял проект с Ionic v3 и v4, была глупая маленькая проблема с функцией ToastController.create. Более новая версия возвращает обещание, и я забыл его await. Думая, что это может стать достойным вопросом «что не так с этим кодом», я создал этот крошечный пример в Ionic-Angular.

ngOnInit() {
  this.presentToast();
}
async presentToast() {
  const toast = await this.toastController.create({
    message: 'Your settings have been saved.',
    duration: 2000
  });
  toast.present();
}

Теперь мне нужно было создать версию React. Проблема с этим планом в том, что в Ionic-React нет ToastController. На самом деле в React нет ни одного из этих классов контроллеров. Быстрый просмотр документации Ionic Component показал мне правильный способ сделать это.

<IonToast
  isOpen={showToast}
  onDidDismiss={() => setShowToast(false)}
  message="Your settings have been saved."
  duration={2000}
/>

Обратите внимание, что версия React в основном декларативна. Вместо внедрения контроллера в мой класс компонентов, как я делаю в Angular, я просто объявляю тег <IonToast> с атрибутами, соответствующим образом привязанными к локальной переменной состояния.

В итоге я сделал что-то очень похожее с элементом управления загрузкой. Код Angular должен выглядеть знакомо, так как он почти идентичен коду Toast.

async ngOnInit() {
  const loading = await this.ionLoading.create(
    {
      duration: 5000,
      message: 'Please wait',
      translucent: true
    }
  );
  await loading.present();
}

LoadingController вводится в конструктор класса компонента, а затем быстро отображается во время функции ngOnInit.

Код React, как и следовало ожидать, также напоминает разметку <IonToast>.

<IonLoading isOpen={true}
  animated={true}
  duration={5000}></IonLoading>

Опять же, объем кода/разметки, необходимый для отображения компонента Loading, настолько лаконичнее, чем код Angular, что это почти смешно.

Мне оставалось только гадать, что еще я мог упустить.

Простые шаблоны

Мой следующий и последний пример — компонент Ionic Modal. Чтобы создать и представить модальный диалог в Ionic-Angular, вам нужно внедрить ModalController в свой компонент, а затем написать некоторый код для его отображения и обработки его событий.

async presentModal() {
  const modal = await this.modalController.create({
    component: ModalComponent,
    componentProps: { value: 123 }
  });
  await modal.present();
  const data = await modal.onDidDismiss();
  console.log(data);
}

Я намеренно опустил код для вызова функции presentModal, что довольно тривиально. Что нетривиально, так это другая вещь, которую я пропустил из вышеизложенного: обратите внимание на ModalComponent, переданное в функцию create? Это определяет все, что касается содержимого модального окна. Где это определено?

Как оказалось, мне нужно создать совершенно отдельный компонент Angular (ng generate component ...) со всеми его вспомогательными файлами. Если вы создаете большой, независимый, модульно-тестируемый компонент, который вы хотите отобразить в виде модального диалогового окна, это имеет смысл. Если вы хотите что-то простое, очень плохо. Вам все еще нужно пройти церемонию. Конечно, вы можете использовать ярлыки, такие как встроенные стили и шаблоны. Вы также можете пропустить модульные тесты, которые, кажется, используются по умолчанию в коде React. Но невозможно обойти указанный выше императивный код ModalController.**

С другой стороны, код React настолько прост, насколько это возможно.

<IonModal isOpen={showModal}>
  <p>This is modal content</p>
  <IonButton onClick={() => setShowModal(false)}>
    Close Modal
  </IonButton>
</IonModal>

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

Заключение

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

Скрипт в разметке

Меня до сих пор не волнует вся предпосылка, стоящая за тем, что заставляет React работать. Меня учили разделять свои заботы. Любая нетривиальная логика внутри моей HTML-разметки раздражает меня, и я никогда не смогу с этим справиться. Тем не менее, я ценю некоторые преимущества, предоставляемые Ionic-React, и признаю, что некоторые из предлагаемых декларативных метафор превосходят императивный код Angular.

Что готовит будущее

К счастью, никакая из этих сведений не должна вас обескураживать по поводу предполагаемого превосходства Ionic-React. Макс Линч, генеральный директор Ionic, недавно заявил, что библиотека Ionic-Angular скоро будет обновлена ​​для поддержки более декларативного синтаксиса. Так что, если вы являетесь разработчиком Angular, как и я, вы сможете воспользоваться этим достаточно скоро. А пока вы можете наслаждаться преимуществами DI, которыми является Angular, выполнять модульное тестирование своих компонентов и уверенно разделять свои проблемы.

* На самом деле, во времена моей работы с ASP.NET подобные вещи были обычным явлением. Я просто забыл о радости от того, что IDE делает это за меня.

** В Ionic 6 компонент <ion-modal> Angular стал более декларативным, как и компонент <IonModal> React.

👉 Хотите больше подобного контента, чтобы улучшить свои технические и профессиональные навыки?

Пожалуйста, ознакомьтесь с моей обширной коллекцией книг и курсов или подпишитесь на мою рассылку по адресу https://walkingriver.gumroad.com 📱