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.

Real-time синхронизация данных между ASP.NET и React

В сентябре прошлого года я выступал на крупнейшей томской конференции — «Городе АйТи» с докладом про синхронизацию данных.

Мы в МЦЦ Томск сейчас ведем разработку CRM системы, в которой такая синхронизация нашла очень удачное применение. Как я и рассказывал в докладе, мы синхронизируем «словари» — редко меняющиеся значения списковых элементов, а также пользователей и роли — потому что обращение к ним требуется почти на каждом экране.

Конечно, в процессе внедрения столкнулись с некоторыми особенностями, о которых в докладе сказано не было:

  1. Мы синхронизируем DTO, но, например, UserDto зависит не только от сущности User БД. Например, она также содержит информацию о ролях. Соответственно, пришлось синхронизировать обновления User’ов при обновлении связанных сущностей.
  2. При инициализации синхронизации на стороне React необходимо следить за последовательностью действий. Мы делаем так:
    1. Стартуем SignalR-соединение и собираем все пришедшие изменения, но не применяем их.
    2. Запрашиваем текущие значения всех сущностей с Backend (GET /users).
    3. После получения списка сущностей применяем все полученные изменения
    4. Продолжаем синхронизацию в обычном режиме (применяем изменения как только они приходят
  3. Процедуру инициализации соединения повторяем при разрыве SignalR-подключения
  4. Не все изменения в сущностях можно получить до вызова SaveChanges(). Например, идентификаторы новых сущностей (для которых будет выполнена команда INSERT) недоступны до SaveChanges(). Таким образом необходимо производить дополнительную обработку списка изменений после SaveChanges.

Если интересны детали или обновленные примеры кода — пишите, обсудим!

А также можете скачать презентацию как приятный бонус :)