О бессерверных функциях, vue-query и ссылках на объекты.

Еще в начале 2020 года, когда я изучал JavaScript, я создал Chartssss, чтобы практиковать объектно-ориентированное программирование в JS. Недавно я решил перестроить его, но на этот раз с использованием Vue.js, чтобы впервые получить практический опыт работы с фреймворком.

О

Chartssss — это простое веб-приложение, которое использует musixmatch API для отображения лучших треков и исполнителей в более чем 80 странах.

Я создал эту версию с помощью Vue.js и использовал vue-query для выборки данных. Я включил простое глобальное хранилище, которое использовал для обмена состоянием между компонентами.

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





CORS, ключи и бессерверные функции

Несмотря на то, что основной целью проекта было изучение Vue.js, он также представил себя как возможность узнать что-то еще новое.

В оригинальном проекте vanilla JS было две проблемы. Во-первых, мои ключи API были доступны в браузере и в моем коде, который находился в общедоступном репозитории GitHub. Во-вторых, я не мог делать запросы к API musixmatch, не будучи заблокированным политикой CORS.

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

Однако на этот раз я хотел создать свой собственный прокси-сервер, чтобы я также мог хранить свои ключи и отправлять запросы к API musixmatch оттуда, а не в браузере. Но давайте просто скажем, что я не тот парень, которому вы звоните, когда вам нужно написать какой-то внутренний код. Так что мне нужно было более простое решение, и тут на помощь пришли бессерверные функции Vercel.

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

Я покопался в документах и ​​через несколько минут нашел свою собственную бессерверную функцию. Я использовал его, чтобы делать запросы к API musixmatch и хранить свои ключи в секрете как в локальном файле .env, так и в моем развертывании Vercel, избегая при этом ошибок CORS, поскольку теперь я делал запросы с сервера, а не с сервера. браузер

Vue-запрос

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

Приходя из мира React, я ранее использовал react-query для выполнения запросов API, и мне особенно нравится его функция кэширования. Где при выполнении запроса, идентифицируемого уникальным ключом несколько раз, он возвращает данные из кеша, если они не устарели, вместо повторной выборки данных по сети .

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

Я также хотел, чтобы кэш работал в моем приложении. Например, если я ранее запрашивал «3 лучших трека в США», я не хотел получать это снова, если это запрашивалось неоднократно. Вместо этого я хотел вернуть данные из первого запроса.

Сначала я начал писать объект данных в памяти, чтобы добиться этого, но потом это стало довольно сложно. Поэтому я обратился к vue-query, аналогу react-query, поддерживаемому той же компанией. Кроме того, мое приложение было очень легким, это был первый и, в конце концов, единственный пакет, который я установил.

Состояние приложения и поток данных

Давайте сделаем небольшое отступление, чтобы немного описать структуру моего приложения. У меня есть два состояния: состояние формы, в котором хранятся входные данные формы по мере их изменения, и глобальное хранилище, которое включает состояние, идентичное состоянию формы. Я использую глобальное хранилище в качестве зависимости в своем vue-запросе для (повторного) извлечения данных из API при их изменении.

Таким образом, поток данных:

  1. По мере заполнения формы состояние формы заполняется входными данными.
  2. В событии отправки формы я обновляю глобальное хранилище данными из состояния формы.
  3. Это изменение в глобальном хранилище запускает повторную загрузку и возвращает данные, необходимые для соответствующего обновления представления.

Но к чему эта дихотомия тождественного состояния? Я не использовал состояние формы для запросов API, потому что не хочу, чтобы они немедленно получали любые входные данные в изменениях формы. Итак, в чем смысл состояния формы? Почему бы не собирать входные данные из формы в ее событии отправки? Потому что мне нужно состояние формы для отображения текста, передающего поисковый запрос, который должен быть выполнен, как показано ниже:

Ссылки на объекты и фантомные обновления

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

Как?

Единственное место во всем моем приложении, где обновлялось глобальное хранилище, было в событии отправки формы. И тем не менее, при повторяющихся обновлениях состояния формы оно обновлялось без возникновения события.

Учитывая, что я был новичком в Vue.js, я предположил, что делаю что-то не так. Поэтому я позвонил более опытному инженеру Vue.js, чтобы узнать, сможем ли мы выяснить проблему. После краткого объяснения он сразу указал на проблему, и моей первой реакцией было «Конечно, как я мог это пропустить». Это была вовсе не проблема Vue.js.

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

Дурак я.

Мы исправили это, передав функцию обновления копию.

Вычисляемые свойства и игнорируемое состояние

А потом был второй; Эта ошибка была конкретно связана с vue-query. Или я так думаю.

Я упомянул, как я передал свой глобальный магазин в качестве ключевой // зависимости для vue-query. Поэтому всякий раз, когда я обновляю его в событии отправки формы, vue-query будет обновляться и возвращать обновленные данные для представления. Но проблема заключалась в том, что всякий раз, когда мой глобальный магазин обновлялся, vue-query этого не замечал.

Чтобы убедиться, что мой глобальный магазин активен, я создал наблюдатель (например, useEffect для тех, кто пишет ответ), чтобы проверить, распознает ли он мое обновление глобального магазина. И это произошло! Так что это начало выглядеть очень странно.

Немного подумав и поработав, я решил передать свое глобальное хранилище как вычисляемое свойство в vue-query в качестве ключа, а не передавать его напрямую. И неожиданно, это сработало.

Я не уверен, почему. Как я уже говорил ранее, наблюдатель распознает обновления глобального хранилища, не будучи вычисляемым свойством. Но я предполагаю, что из-за того, что я не инициализировал глобальное хранилище в том же файле компонента, что и запрос, оно находится в другом контексте, отличном от внутренних компонентов запроса, и, следовательно, не может отслеживать его обновления. Я надеюсь, что пойму это, когда узнаю больше о Vue.js.

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

Спасибо за чтение, и до следующего раза!