Оркестрация staggerContainer/staggerItem у framer-motion раздаёт детям
команду «показаться» один раз — при анимации родителя на mount. Дети,
смонтированные позже (когда resolve'ится запрос react-query), в
оркестрацию не попадают и навсегда остаются в initial (opacity: 0, y: 8).
Симптом: после жёсткой перезагрузки (F5) на странице виден только
заголовок — карточки есть в DOM, но прозрачны. При SPA-навигации кэш
react-query тёплый, дети монтируются вместе с родителем — поэтому баг
проявлялся только при холодном заходе и маскировался на проде (нет
StrictMode, same-origin API, тёплый кэш почти всегда выигрывают гонку
с ~300-мс окном анимации).
Два способа фикса в зависимости от формы страницы:
1. key={isLoading ? 'loading' : 'ready'} на контейнере — перемонтирование
после загрузки, stagger проигрывается заново уже со всеми детьми.
Для страниц, где весь контент асинхронный (каскад сохраняется):
- ConnectedAccounts — карточки провайдеров
- SavedCards — список сохранённых карт
2. Явные initial="initial" animate="animate" на условном staggerItem —
элемент анимирует себя сам, не дожидаясь оркестрации родителя. Для
страниц, где асинхронны только 1-2 опциональные карточки (не
перезапускает анимацию всей страницы на каждый resolve):
- Balance — «Способы пополнения» и ссылка «Сохранённые карты»
- Support — карточка «Написать нам» (support_type='both')
- Profile — реферальный виджет
Попутно: в Wheel у контейнера истории спинов стояли несуществующие
варианты initial="hidden"/animate="show" (у staggerContainer/staggerItem
ключи — initial/animate/exit), из-за чего stagger там молча не работал
вовсе; имена исправлены.
Проверено и не требует правок: TopUpAmount (early-return до загрузки
методов), TopUpMethodSelect и MergeAccounts (динамический контент —
обычный HTML внутри всегда смонтированных staggerItem), вложенный
контейнер транзакций в Balance (самоанимирующийся).