Оптимизация интерактивных интерфейсов: React-шахматы на WASM

#react#wasm#performance#rust

TL;DR

Разбираем кейс ультраоптимизированного React-компонента шахматной доски с WASM-движком на Rust. Ключевые фичи: нулевые ререндеры при драге, подписка на отдельные клетки через useSyncExternalStore, Canvas для оверлеев и Web Animations API. Бандл <16 KB gzip.

Введение: почему это интересно

В эпоху SPA с их вечными проблемами перформанса, кейс шахматной доски от yahorbarkouski демонстрирует, как сочетание React, WASM и грамотной архитектуры позволяет достичь нативного уровня отзывчивости. Особенно показательно решение проблемы “драг без ререндеров” — больного места многих интерактивных интерфейсов.

Архитектурные решения

1. State management на уровне клеток

Вместо классического подхода с хранением состояния всей доски в React, здесь используется Uint8Array(64) (WASM shared memory), где каждый элемент соответствует клетке:

// Подписка клетки на свое состояние
const useSquare = (index: number) => {
  return useSyncExternalStore(
    (callback) => store.subscribe(index, callback),
    () => store.getSnapshot(index)
  );
};

Это дает точечные обновления — при ходе меняются только 2-4 клетки вместо всей доски.

2. Drag-n-drop без участия React

Драг реализован через отдельный слой на refs + Web Animations API:

const pointerLayer = useRef<HTMLDivElement>(null);

useEffect(() => {
  const el = pointerLayer.current;
  if (!el) return;

  el.addEventListener('pointermove', (e) => {
    // Анимация через WAAPI, минуя React
    pieceToDrag.animate(
      { transform: `translate(${e.clientX}px, ${e.clientY}px)` },
      { duration: 0, fill: 'forwards' }
    );
  });
}, []);

3. Canvas для оверлеев

Все стрелки и подсветки рисуются на Canvas, что исключает лишние DOM-элементы:

const drawArrow = (ctx: CanvasRenderingContext2D, from: Square, to: Square) => {
  const [x1, y1] = getCoords(from);
  const [x2, y2] = getCoords(to);
  // ... векторная математика ...
  ctx.beginPath();
  ctx.moveTo(x1, y1);
  ctx.lineTo(x2, y2);
  // ... стилизация ...
};

Практические выводы

Когда стоит применять подобные оптимизации?

  1. Высокочастотные интеракции (драг, ресайз, скролл)
  2. Крупные grid-интерфейсы (таблицы, карты)
  3. Строгие требования к FPS (игры, анимации)

Альтернативы WASM

Для менее требовательных сценариев можно обойтись:

Заключение

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

Для глубокого погружения рекомендую изучить:

  1. Исходники ultrachess-react
  2. Доку по Web Animations API
  3. Rust и WASM

Источник: https://www.reddit.com/r/reactjs/comments/1ssjy2i/built_an_ultrafast_react_chessboard_1_commitmove/