Реализация совместного редактирования таблицы в реальном времени в мобильном приложении
Таблица — не текст. У неё есть структура: строки, столбцы, ячейки, формулы, зависимости между ячейками. Алгоритмы синхронизации, которые работают для текстовых документов (Y.js YText, CRDT для последовательностей), здесь применяются иначе. Конкурентное изменение ячейки B3 и одновременное изменение формулы =SUM(B1:B5) в C1 — это два независимых события с зависимостью по данным.
Модель данных: не массив строк, а Map ячеек
Таблица в CRDT-представлении — это Y.Map (или аналог), где ключ — "row:col" строка, значение — объект ячейки. Y.js YMap поддерживает конкурентные операции на уровне отдельных ключей: два пользователя редактируют разные ячейки одновременно — нет конфликта. Два редактируют одну ячейку — побеждает последняя запись (Last-Write-Wins семантика).
const ycells = ydoc.getMap('cells');
ycells.set('3:2', { value: '=SUM(A1:A3)', formatted: '15', style: { bold: true } });
ycells.observe(event => {
event.changes.keys.forEach((change, key) => {
if (change.action === 'update' || change.action === 'add') {
const [row, col] = key.split(':').map(Number);
recalculateAffectedFormulas(row, col);
rerenderCell(row, col);
}
});
});
Last-Write-Wins для ячеек — приемлемо в большинстве сценариев. Для критических данных (финансовые таблицы) нужен конфликт-детектор и UI для ручного resolve.
Добавление и удаление строк/столбцов: структурные изменения
Это сложнее, чем изменение ячейки. Вставка строки перед строкой 5 должна сдвинуть все ссылки в формулах: =B5 становится =B6. Конкурентная вставка строки двумя пользователями — порядок вставки влияет на финальную структуру.
Y.js YArray для списка строк с YMap для каждой строки — классическая схема. При вставке в YArray CRDT гарантирует детерминированный порядок merge (основан на clientId и clock). Формулы после структурных изменений нужно пересчитывать через dependency graph.
Пересчёт формул — тема отдельная. HyperFormula (hyperformula.js) — open-source движок формул (аналог Excel), работает в JavaScript. Поддерживает 400+ функций. Интегрируется с Y.js: при получении CRDT-обновления применяем его к HyperFormula через setSheetContent() и получаем пересчитанные значения.
Мобильный рендеринг таблицы
FlashList (React Native) с двумерной прокруткой — нестандартный кейс. Стандартный FlatList / ScrollView не оптимизирован для больших таблиц с заморозкой заголовков и виртуализацией ячеек.
Решения:
-
react-native-table-component— простой, нет виртуализации, не для больших таблиц. -
react-native-spreadsheet— есть, но давно не обновлялся. - Кастомный рендерер на
react-native-gesture-handler+react-native-reanimated— полный контроль, виртуализация вручную.
На нативном Android: RecyclerView с GridLayoutManager, виртуализация встроена. На iOS: UICollectionView с UICollectionViewCompositionalLayout для двумерной прокрутки со свободными размерами ячеек.
Кастомная ячейка-редактор: TextInput с поддержкой формул (начинается с = — переключаем режим). На iOS autocorrect ломает формулы (=SUM превращается в =Sum или подчёркивается). Нужно autocorrectionType = .no и spellCheckingType = .no для ячеек в режиме формулы.
Выделение диапазона: B2:D5
При вводе формулы пользователь должен кликнуть на ячейку и перетащить для выбора диапазона — классический Excel-UX. На мобиле: кастомный gesture recognizer поверх таблицы, который отслеживает pan gesture и вычисляет диапазон ячеек по координатам. Нужен hitTest для определения ячейки по точке касания.
Одновременно несколько пользователей могут выбирать диапазоны — показываем через Awareness Protocol (как курсоры в текстовом редакторе), но с цветовой кодировкой по пользователю.
Синхронизация через WebSocket: оптимистичное обновление
Локальное изменение ячейки применяется к UI немедленно (optimistic update). Параллельно Y.js кодирует операцию в update binary и отправляет на сервер. Сервер рассылает update другим клиентам. Если пришёл конфликтующий update — Y.js merge применяется, UI перерисовывается.
Для больших таблиц (1000+ строк) важно не перерисовывать всю таблицу при каждом remote-обновлении. Отслеживаем event.changes.keys в observer'е и перерисовываем только изменившиеся ячейки + зависимые формулы.
Оценка
MVP с Y.js + HyperFormula на React Native (до 100 строк, базовые формулы, 2–3 одновременных пользователя) — 10–16 недель. Полноценный Google Sheets-подобный мобильный редактор с тысячами строк, сложными формулами и структурными изменениями — 6–12 месяцев.







