Посмотрите короткую демонстрацию приложения здесь!

Как веб-разработчик, я обычно подхожу к идеям приложений, исследуя свои повседневные задачи и оценивая, как я могу использовать технологии для их оптимизации. Несколько месяцев назад нам с мужем нужно было заказать Uber, и моя первая мысль была: «Как мы узнаем, будет ли Lyft дешевле?» Вы можете получить ориентировочную цену до того, как закажете поездку, но необходимость запрашивать оценку из каждого приложения отнимает много времени. Именно тогда я решил, что хочу создать приложение, которое будет выполнять всю эту работу по сравнению цен за меня. Идея заключалась в том, чтобы иметь возможность ввести начальное местоположение и пункт назначения, проверить компонент карты на точность геокодирования, а затем получить полный спектр типов поездок и текущие оценки как Uber, так и Lyft, чтобы вы могли не платить больше за ту же поездку. .

Первым шагом в создании этого приложения была привязка областей ввода для начальных и конечных местоположений. Хотя я мог бы создать и стилизовать для этого свои собственные поля ввода, я не хотел тратить слишком много времени на стилизацию, поэтому решил импортировать предварительно стилизованные компоненты поля из Semantic-UI. Импортировать их - одно дело; в основном я просто обернул компонент в свой собственный компонент; так же, как и поле ввода HTML. Однако компоненты Semantic-UI имеют так много предустановленных свойств и опций, что вы действительно можете их настраивать. Поначалу поиск их названий / значений может быть немного сложным. В конце концов, научиться читать их документы было действительно полезно, и я перешел на чтение документации по API Google, Uber и Lyft по мере того, как я продолжал создавать.

Я надеялся использовать функцию автозаполнения Google Places, когда пользователь вводил свое местоположение в раскрывающуюся область ввода, но я узнал, что при этом я буду взимать с моей учетной записи около 0,012 доллара за каждую набранную букву. Из-за боязни достичь лимита бесплатных запросов я решил, что API Адресов заполняет только предложенные местоположения после того, как пользователь введет общее местоположение и нажмет "Отправить". Таким образом, API был задействован только один раз, и я предотвратил любую сумасшедшую переполнение запросов к моему ключу API. Теперь у меня настроен входной компонент с его собственным состоянием, начальным / конечным местоположениями. После отправки эта строка отправляется в Google Адреса, который отправляет обратно массив из 5 предложенных местоположений. Эти местоположения хранятся в redux, а затем отображаются в моем поисковом компоненте для отображения в виде раскрывающегося меню. Когда пользователь выбирает одно из раскрывающихся меню, он обновляет состояние локального компонента, чтобы сохранить официальный адрес. Когда оба местоположения найдены и сохранены как местоположение Google Адресов, форма отправляется на следующую страницу.

Следующая страница будет содержать простой компонент карты, который нанесет на карту два местоположения, чтобы убедиться, что они верны. Все карты в этом смысле должны выполняться с геокодированными координатами, чему я научился в ходе этого проекта. Направления; запросы на поездку; карта отображает и т. д., все они работают с геокодированными координатами, а не с почтовыми адресами. Проблема в том, что геокодирование также является очень дорогостоящей и утомительной задачей, так как запросы на геокодирование от Google идут по цене 0,5 доллара США КАЖДЫЙ. Желая избежать случайного завышения платы за мою учетную запись, я приложил все усилия, чтобы попробовать другую службу геокодирования. Я обнаружил, что MapBox намного дешевле, но также очень неточен при использовании с поиском Google Адресов. Их поиск мест с автозаполнением также был неточным; поскольку в Google есть встроенная привязка местоположения, а в MapBox ее нет. Если я искал «Ферри-билдинг» с помощью Google API, предлагаемые местоположения знали по моему IP-адресу, что я был недалеко от Сан-Франциско, поэтому мне были показаны результаты только для Ферри-билдинг в моем обычном районе. Mapbox показал Пенсильванию, Массачусетс, даже что-то в Южной Америке по тому же запросу. Чтобы вернуться и использовать их картографические сервисы, мне пришлось бы добавить еще одно поле, которое заставляло бы пользователя вводить свой город / штат, отправить его, чтобы настроить область привязки, а затем позволить им искать свои начальные / конечные местоположения. . Мало того, что это было похоже на много ненужной работы для получения желаемых результатов, но и поток на странице действительно испортил бы UI / UX, к которому я стремился.

В конце концов, я остановился на геокодировщике Google и просто решил, что пока не буду публиковать это приложение для публичного использования, чтобы предотвратить накопление этих расходов. Однако я использовал компонент MapBox Map, так как обнаружил, что их пакет React действительно чистый и простой в использовании. Единственная проблема, с которой я столкнулся, заключалась в том, чтобы их маркеры местоположения работали. Кажется, это обычная проблема, когда многие значки, которые они предлагают для этих маркеров, просто не отображаются. Я пробовал довольно много, но в итоге мне пришлось выбрать маленькие звездочки просто потому, что я, по крайней мере, могу видеть их на странице. Я хотел бы иметь возможность изменить их цвета (по умолчанию они были коричневыми), но мне еще не удалось заставить это работать.

Итак, пользователь отправил свои начальные и конечные местоположения, API геокодирования Google творит чудеса, и местоположения отображаются на компоненте карты на следующем маршруте. Если это правильно, пользователь может перейти к разделу Uber / Lyft, если нет, есть кнопка, которая позволяет вам вернуться и ввести новые местоположения. Прискорбная реальность такова, что API геокодирования Google, работающий с MapBox, по-прежнему не на 100% точен, а иногда одно местоположение просто не отображается на карте. Я считаю, что это ошибка на стороне сопоставления, поскольку обычно запросы все еще могут быть отправлены в Uber / Lyft с ответом. Это означает, что эти геокодированные местоположения находятся * там *, их просто нельзя отобразить на карте. Поскольку это приложение не будет сразу запущено в производство, я просто оставлю его на следующий день.

На последнем маршруте происходит волшебство. Эти координаты с карты отправляются одновременно в Uber и Lyft. Мне пришлось реализовать некоторые async / await в этих методах выборки, чтобы убедиться, что мои компоненты будут обновляться правильно, что было забавно. Я слышал об async / await, но у меня еще не было возможности опробовать их до сих пор. После выполнения обоих запросов на выборку компоненты обновляются оценками цен для каждого типа поездки (Uber X, Shared, Uber Black и т. Д.) И текущим диапазоном оценок для каждого типа. Было бы неплохо, если бы их API возвращали оценку в долларах, но оба чаще всего возвращают диапазон. Оценка Lyft возвращается в центах, поэтому мне пришлось использовать другую функцию, которая отображала результаты и преобразовывала их в более удобочитаемую стоимость. Вместо 1900–2000 центов я сохранил их оценки как «19–20 долларов», чтобы соответствовать формату Uber. После этого единственная проблема, оставшаяся на стороне клиента, заключалась в том, чтобы убедиться, что два компонента результатов загружаются одновременно, что включало добавление загрузчика к компоненту, который будет запускаться во время загрузки обоих результатов. И вуаля!

Этот проект был сложен по нескольким причинам; было много вызовов API и обработки внешних данных. Также было много очень специфических функций UI / UX, которые я хотел реализовать, которые включали передачу состояния redux по маршрутам, использование компонентов Semantic-UI и стили. Но в целом все прошло довольно гладко. В целом это очень маленькое приложение с точки зрения использования, но бэкэнд громоздкий и очень мощный. Приятно иметь возможность создать приложение, которое служит реальной цели и может помочь людям сэкономить деньги. Теперь мне нужно выяснить, как избежать накопления десятков тысяч долларов на оплату API, сделав это общедоступным мобильным приложением.