Свой QR-генератор на React: когда готовые решения не подходят

#react#svg#qrcode#frontend

Когда последний раз вам приходилось копаться в исходниках библиотеки для генерации QR-кодов? Я — на прошлой неделе. Поводом стал типичный кейс: клиенту нужно встроить QR в интерфейс, но с нестандартным дизайном — градиенты, логотипы, анимированные паттерны.

Почему не qrcode.react?

Начну с боли: большинство React-библиотек для QR либо рендерят через canvas (что убивает кастомизацию), либо представляют собой чёрный ящик с ограниченными возможностями стилизации. Популярный qrcode.react хоть и использует SVG, но:

  1. Не даёт доступа к отдельным модулям QR (позиционные маркеры, тайминг-линии)
  2. Генерирует монолитный path, где нельзя точечно менять стили
  3. Имеет скрытые зависимости типа qr.js

Мой эксперимент начался с вопроса: а что если собрать велосипед, но с правильной геометрией руля?

Архитектура кастомного решения

Библиотека строится вокруг трёх ключевых принципов:

  1. Чистый SVG — никакого canvas для максимальной гибкости
  2. Нулевые зависимости — даже QR-энкодер написан с нуля
  3. Компонентный подход — каждый элемент QR-кода доступен для кастомизации

Вот как выглядит базовый пример использования:

<QRCode
  value="https://frontend.tools"
  modules={({ x, y }) => (
    <rect
      x={x}
      y={y}
      width={1}
      height={1}
      fill={Math.random() > 0.5 ? '#f00' : '#00f'}
    />
  )}
/>

Где modules — render-prop для точечного управления отрисовкой каждого модуля QR-кода. Для сравнения, в других библиотеках вам бы пришлось перекрывать элементы через CSS хаки или постобработку SVG.

Под капотом энкодера

Самая интересная часть — реализация алгоритма QR-кодирования. Вот что пришлось учесть:

Особенность моего подхода — разделение логики и представления. Энкодер возвращает чистую матрицу данных, которую затем можно рендерить любым способом:

const matrix = encodeQR('Hello world', { errorCorrection: 'H' });
// matrix = [[0,1,0,1,...], ...]

Это открывает возможности для:

Производительность и ограничения

На практике столкнулся с двумя проблемами:

  1. Рендер крупных QR-кодов (версия 40) — React начинает тормозить при 2000+ модулях. Решение — виртуализация через react-window.
  2. Генерация в Web Worker — энкодинг сложных payloads может блокировать UI. Вынес обработку в worker-ы, но это усложнило bundle.

Неожиданно полезным оказался прием с memoization компонентов модулей — это дало +15% к скорости рендера при частых обновлениях.

Когда стоит брать этот подход

Моя библиотека — не замена готовым решениям, а инструмент для специфичных кейсов:

Если же вам нужно просто быстро вставить стандартный QR — возможно, лучше взять проверенную библиотеку. Но когда требования выходят за рамки обычного — приходится писать свой код. И да, это того стоило.

P.S. Демо с живыми примерами кастомизации: qrcode.ttsalpha.com. Критика и пул-реквесты приветствуются — особенно по части оптимизации энкодера.


Источник: https://qrcode.ttsalpha.com