На моей нынешней работе мы пытаемся создать лучшее программное обеспечение для наших клиентов. Одна из самых сложных и запутанных частей разработки программного обеспечения — не усложнять. В Crewmeister мы решили использовать React для всех новых частей пользовательского интерфейса, которые мы разрабатываем. Поскольку React — это только уровень представления приложения, нам, как разработчикам, все еще нужно выяснить, как мы структурируем наше приложение. Марсель Боймер написал об этом большую статью. Очень рекомендую прочитать.
В этой статье будет представлен обзор того, как мы структурировали наше клиентское приложение и как мы различаем состояние пользовательского интерфейса и обычное состояние приложения.
Архитектура Вяза
Elm — строго типизированный функциональный язык программирования, который компилируется в JavaScript. В настоящее время он в основном используется для разработки на стороне клиента, поскольку elm предпочитает архитектуру, ориентированную на приложения пользовательского интерфейса. Архитектура Elm описывает 3 основных компонента.
- Модель или состояние приложения
- Просмотр или пользовательский интерфейс
- Обновления или действия
модель или состояние приложения представляет собой все данные приложения, необходимые для отображения определенного пользовательского интерфейса.
Представления — это чистые функции (сравнимые с реагирующими функциями без сохранения состояния), которые получают модель в качестве аргумента.
Обновления — это функции, которые изменяют модель. Эти функции могут быть запущены из пользовательского интерфейса.
Эти 3 компонента являются основным компонентом нашего клиентского приложения. Если вы хотите узнать больше об архитектуре Elm, вам следует ознакомиться с официальным Руководством по Elm.
Состояние приложения и состояние пользовательского интерфейса
В экипаже все состояние приложения разделено на две составляющие. Состояние пользовательского интерфейса и состояние приложения.
Состояние приложения содержит все данные, относящиеся к основным функциям приложения. Это место, где хранится важная для бизнеса информация. В приложении чата это будет список пользователей и сообщений.
Состояние пользовательского интерфейса — это данные, которые не требуются приложению, но необходимы для улучшения взаимодействия с пользователем. Отображение счетчика во время отправки формы — прекрасный пример состояния пользовательского интерфейса.
Во многих приложениях эти два состояния смешиваются в одном объекте глобального состояния. Если пользовательский интерфейс приложения изменяется, объект глобального состояния также необходимо изменить. Это приводит к тесной связи между логикой приложения и поведением пользовательского интерфейса.
Поскольку мы хотим, чтобы логика пользовательского интерфейса была как можно ближе к нашим компонентам реакции, мы решили, что все состояние пользовательского интерфейса находится в самих компонентах реакции. Поскольку обращение к глобальному хранилищу смешивало бы состояние пользовательского интерфейса с состоянием приложения, мы решили обрабатывать все поведение пользовательского интерфейса в самих компонентах. Поскольку действия могут вызвать изменение пользовательского интерфейса (например, показать счетчик загрузки), мы решили, что все действия возвращают обещания. Синхронные действия также возвращают промисы, поскольку мы хотим сохранить согласованный интерфейс. Благодаря этому дополнению можно обрабатывать все состояния пользовательского интерфейса в реагирующих компонентах независимо от логики приложения.
Простой пример будет выглядеть так:
Действие signIn (строка 5) возвращает обещание, которое выполняется за 1 секунду. Это действие передается компоненту SignInScreen (строка 40). Поскольку мы хотим отобразить загрузочный экран, пока действие выполняет свою работу, переданное действие оборачивается в другую функцию, чтобы можно было установить состояние пользовательского интерфейса. Каждый раз, когда пользователь нажимает кнопку, экран загрузки будет отображаться до тех пор, пока действие не завершится.
Представляем обещанный картофель фри
Одна проблема, с которой мы столкнулись в crewmeister, заключалась в том, что в некоторых случаях наши действия реагировали так быстро, что наши клиенты не осознавали, что они действительно были выполнены. Клиенты, использующие наше автономное приложение First React, звонили в нашу службу поддержки, чтобы сообщать об ошибках и проблемах из-за быстрого пользовательского интерфейса. Вот почему мы создали обещание фри.
Promise frites — небольшая служебная библиотека для промисов. В отличие от других библиотек обещаний, promise frites не оборачивает весь объект обещания и добавляет к нему дополнительную функциональность. Одна из функций, представленных в этой библиотеке, называется waitAtleast. Он принимает продолжительность в секундах в качестве аргумента и возвращает новую каррированную функцию, которая будет ждать по крайней мере заданную продолжительность, прежде чем она разрешится.
В компоненте реагирования эта функция может использоваться для отображения экрана загрузки не менее 1 секунды, чтобы наши клиенты думали, что работа выполняется в фоновом режиме. Другой вариант использования этой функции — предотвращение мерцания пользовательского интерфейса в быстрых сетях.
Добавление этой функции в наш компонент реагирования отключает мерцание в пользовательском интерфейсе. Несмотря на то, что я не большой поклонник добавления дополнительного времени ожидания для наших клиентов, мы видели, что люди думают, что приложение каким-то образом не работает, если они нажимают кнопку, и оно немедленно возвращается из состояния загрузки.
Уведомлять пользователя, когда что-то занимает очень много времени
Уведомление пользователя, когда ожидается, что что-то займет некоторое время, является сложной задачей для реализации. Получение местоположения GPS в браузере является такой задачей. Поскольку для получения геолокации с достаточно высокой точностью требуется до 6 секунд, мы хотели, чтобы наши пользователи знали, что что-то происходит. В этом случае может помочь функция executeWhenUnResponse. В настоящее время в нашем приложении мы используем эту функцию для отображения различного загружаемого текста по прошествии определенного времени.
Promise-frites добавляет еще пару полезных утилит, которые делают работу с промисами еще более приятной. Повторная попытка обещаний или отказ от них, если это занимает много времени, — это просто установка npm.
Вывод
Возврат обещаний из действий позволяет потерять связь между состоянием пользовательского интерфейса и состоянием приложения. Каждый раз, когда пользовательскому интерфейсу необходимо адаптироваться, логика приложения может оставаться неизменной. Поскольку нам нужно разделить некоторую логику приложения между нашим родным приложением React и нашим браузерным приложением, мы можем повторно использовать хранилище и действия в обоих приложениях.
Разделение состояния пользовательского интерфейса и состояния приложения помогает нам получить четкое представление о том, что происходит внутри нашего приложения. Использование promise-frites помогло нам уменьшить сложность пользовательского интерфейса.
Привет, меня зовут Томас Майрхофер, я разработчик полного стека, работающий в компании Crewmeister в Мюнхене. Если вам нравится работать с нами, просто отправьте мне сообщение @webpapaya в Твиттере.