usePreserveForm — React-хук для сохранения состояния формы при F5 (на основе react-hook-form)

Мы в МЦЦ Томск уже давно и с удовольствием используем react-hooks. В новых компонентах и проектах мы используем исключительно функциональные компоненты, и от оставшихся класс-компонентов тоже потихоньку отказываемся. При переходе на функциональные компоненты мы с удовольствием сменили и компонент для управления формами и валидацией. Мы остановились на react-hook-form.

Есть множество сравнений с Formik или Redux-Form, в которых react-hook-form безоговорочно выигрывает, прежде всего за счет использования неконтролируемых input’ов. Эта техническая деталь делает UX работы с формами в разы лучше: все ведь сталкивались с «тормозами» React’а при заполнении форм (например, когда CPU компьютера сильно нагружен чем-то другим)? Ну так вот с «неконтролируемыми» input’ами это просто невозможно :) Ну и кроме этого важного преимущества, react-hook-form просто приятен для разработчика — для работы с ним требуется минимум дополнительного кода.

Однако, одно из свойств redux-form при переходе на react-hook-form мы потеряли. Например, когда пользователь частично заполнил форму и нажал F5 — все заполненные поля обнулятся. Это особенно обидно, если форма большая и полей заполнено много. Такая потеря данных случается и не только при нажатии F5, а, например, при случайном закрытии браузера, или перезагрузки компьютера. Очень хотелось бы, чтобы пользовательский ввод в таких случаях сохранялся.

В redux-form такое поведение мы получаем «из коробки», здесь же пришлось добавить немного кода. Встречайте, мой первый npm-пакет use-preserved-form. Использовать пакет очень легко — просто вместо вызова useForm необходимо вызывать usePreservedForm.

Подробные инструкции можно также почитать в github-репозитории или посмотреть на пример вживую.

Приятного использования!

How to add ESLint/Prettier support to create-react-app

This is a short reminder for myself about adding ESLint support to a new create-react-app project with typescript (which is my default frontend template for now).

Instructions include setting up file watchers in VSCode and WebStorm, so all files are automatically formatted on save.

So, here we go.

yarn add @typescript-eslint/parser @typescript-eslint/eslint-plugin prettier eslint-config-prettier eslint-plugin-prettier

Extract the configs from archive into the folder of a project. This will set up watchers and default configs for both ESLint and Prettier.

Don’t forget to restart your IDE to get all the goodies.

OAuth в SPA или неожиданные сложности интеграции логина через соцсети в React с Asp.Net Core

Это история про то, как казалось бы типичная задача интеграции входа через соц.сети в React/Asp.Net Core приложении может превратиться в длинную сагу и закончиться open-source библиотекой :)

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


В Asp.Net Core существует замечательная встроенная интеграция с внешними провайдерами аутентификации (OAuth/OpenId и прочее нестандартное), а также сторонние плагины, поддерживающие аутентификацию даже через VK. Однако весь этот механизм подразумевает, что у вас обычное server-side приложение (с forms-авторизацией), и никаких собственных access_token’ов, которые привычны в SPA вам генерироваться не будет.

Вот вот мне и загорелось желание воспользоваться всем этим огромным количеством готовых решений и подружить его с SPA. Как схема работы должна выглядеть в идеале? Согласно AuthCode Flow (который считается рекомендуемым для использования в SPA), это должно выглядеть примерно так:

SPA получает AuthCode у стороннего провайдера и передает его на бэкэнд приложения. Бэкэнд проверяет верность кода, ищет этого пользователя в своей БД (и создает, если требуется) и возвращает на фронтенд access_token, с которым и происходят все дальнейшие запросы.

Для первого шага (получения AuthCode) в SPA существуют готовые реализации в виде, например, реакт-компонентов. Но под каждого OAuth-провайдера они разные, и подбор и настройка могут отнять достаточно много времени. После интеграции написанной библиотеки IdentityOAuthSpaExtensions (и настройки бэкэнд-части согласно инструкциям от майкрософта), запрос AuthCode из SPA будет состоять из двух частей:

  1. Создание обработчиков и подписка на события:
  2.     window.addEventListener("message", this.oAuthCodeReceived, false);
        function oAuthCodeReceived(message) {
            if (message.data && message.data.type === 'oauth-result') {
                if (data.code) {
                    externalAuthSuccess(data.provider, data.code);
                } else {
                    externalAuthError(data.provider, data.error, data.errorDescription);
                }
            }
        }
        function externalAuthSuccess(provider, code) {
            alert(`Provider: ${provider}, code: ${code}`);
        }
        function externalAuthError(provider, error, errorDescription) {
              alert(`Provider: ${provider}, error: ${error}, ${errorDescription}`);
        }
    
  3. Старт процедуры авторизации:
   window.open(`${window.location.protocol}//${window.location.hostname}:${window.location.port}/external-auth/challenge?provider=${provider}`, undefined, 'toolbar=no,menubar=no,directories=no,status=no,width=800,height=600');

В результате этого ваше SPA получит AuthCode стороннего провайдера. В дальнейшем с ним можно делать что угодно ( :)), но в нашем случае, мы хотим получить access_token от нашего бэкэнда, чтобы в дальнейшем все http вызовы совершать с этим access_token’ом. Для этого в библиотеке существует возможность проверки AuthCode («), а также (рекомендуемая) интеграция с IdentityServer в виде extension grant’a. Описание интеграции очень подробно описано на гитхабе

Итоговая схема выглядит как-то так:

Из основных плюсов библиотеки:

  1. Единая точка входа и общий интерфейс интеграции любых Auth-провайдеров (не нужно менять SPA, меняется лишь одна переменная — имя провайдера — при открытии URL авторизации)
  2. Использование стороннего кода для взаимодействия с OAuth (саму библиотеку не придется обновлять, если в сторонних OAuth что-то изменится).
  3. Добавление новых провайдеров происходит стандартным способом (по инструкции для server-side приложений) и не требует модификации самой библиотеки

Пользуйтесь, задавайте вопросы и рассказывайте об успешных сценариях внедрения!

Доклад про WebAssembly на Городе IT

10 сентября выступил на секции Enterprise конференции Город IT с докладом по WebAssembly.
С моей точки зрения, WebAssembly — это очень перспективное направление, хоть и не готовое к продакшену прямо сейчас. Но нам — разработчикам — просто необходимо внимательно следить за технологиями, которые уже в ближайшее время могут радикально изменить ситуацию в мире фронтэнда.
В докладе рассказывал про появление и развитие WebAssembly, языки и фреймворки, которые его используют, и показал возможности применения Майкрософтоской библиотеки Blazor для разработки SPA с использованием любых существующих .net библиотек (netstandard).
Спасибо всем участникам конференции за интерес и плодотворную дискуссию!

Презентация — уже сегодня на Slideshare, надеюсь на скорое появление видео (ждём организаторов!)
WebAssembly.pptx