
- DATA_SYNCHRONIZATION_RULES.md - правила синхронизации между компонентами - GRAPHQL_CACHE_RULES.md - настройки кеширования и fetchPolicy - CSS_LAYOUT_SCROLL_RULES.md - решение проблем с overflow и scroll - STATISTICAL_COMPONENTS_RULES.md - правила Master-Detail архитектуры Документация основана на исправлениях в кабинете фулфилмента 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
13 KiB
13 KiB
🔄 ПРАВИЛА КЕШИРОВАНИЯ GRAPHQL И FETCHPOLICY
Цель: Обеспечить корректное кеширование GraphQL данных и предотвратить проблемы синхронизации между компонентами
📋 ОСНОВНЫЕ ПРИНЦИПЫ КЕШИРОВАНИЯ
1. СИНХРОНИЗАЦИЯ СВЯЗАННЫХ КОМПОНЕНТОВ
// ✅ ПРАВИЛЬНО - одинаковые настройки для связанных данных
const masterComponent = useQuery(GET_WAREHOUSE_STATS, {
fetchPolicy: 'cache-and-network',
pollInterval: 30000,
errorPolicy: 'all',
})
const detailComponent = useQuery(GET_SUPPLIES_DETAILS, {
fetchPolicy: 'cache-and-network', // ← ОБЯЗАТЕЛЬНО то же самое!
pollInterval: 30000, // ← ОБЯЗАТЕЛЬНО то же самое!
errorPolicy: 'all', // ← ОБЯЗАТЕЛЬНО то же самое!
})
// ❌ НЕПРАВИЛЬНО - разные настройки создают рассинхронизацию
const masterComponent = useQuery(GET_WAREHOUSE_STATS, {
fetchPolicy: 'cache-and-network',
})
const detailComponent = useQuery(GET_SUPPLIES_DETAILS, {
// default fetchPolicy: 'cache-first' - СОЗДАЁТ ПРОБЛЕМУ!
})
2. ОБЯЗАТЕЛЬНЫЕ FETCH POLICIES ПО ТИПАМ КОМПОНЕНТОВ
Dashboard и Статистика
useQuery(DASHBOARD_QUERY, {
fetchPolicy: 'cache-and-network', // Всегда актуальные данные
pollInterval: 30000, // Обновление каждые 30 сек
errorPolicy: 'all', // Показывать частичные данные при ошибках
})
Связанные компоненты (Master-Detail)
// Все компоненты одной функциональности ДОЛЖНЫ иметь идентичные настройки
const sharedQueryOptions = {
fetchPolicy: 'cache-and-network' as const,
pollInterval: 30000,
errorPolicy: 'all' as const,
}
// Применение во всех связанных компонентах
useQuery(MASTER_QUERY, sharedQueryOptions)
useQuery(DETAIL_QUERY, sharedQueryOptions)
useQuery(STATS_QUERY, sharedQueryOptions)
Списки и таблицы
useQuery(LIST_QUERY, {
fetchPolicy: 'cache-and-network', // Актуальные данные
pollInterval: 60000, // 1 минута для списков
notifyOnNetworkStatusChange: true, // Показывать статус загрузки
})
Редко изменяющиеся данные
useQuery(STATIC_DATA_QUERY, {
fetchPolicy: 'cache-first', // Кеш приоритетен
pollInterval: 300000, // 5 минут
errorPolicy: 'ignore', // Не показывать ошибки для статичных данных
})
🏢 СПЕЦИФИЧЕСКИЕ ПРАВИЛА ДЛЯ ФУЛФИЛМЕНТА
ГРУППЫ СИНХРОНИЗИРОВАННЫХ КОМПОНЕНТОВ
Группа 1: Складская статистика
// Все эти компоненты ДОЛЖНЫ использовать одинаковые настройки:
const warehouseStatsOptions = {
fetchPolicy: 'cache-and-network' as const,
pollInterval: 30000,
errorPolicy: 'all' as const,
}
// 1. Главный dashboard (/fulfillment-warehouse)
useQuery(GET_WAREHOUSE_STATS, warehouseStatsOptions)
// 2. Подраздел расходников (/fulfillment-warehouse/supplies)
useQuery(GET_SUPPLIES_STATS, warehouseStatsOptions)
// 3. Раздел услуг (/services) - вкладка "Расходники"
useQuery(GET_SERVICE_SUPPLIES, warehouseStatsOptions)
Группа 2: История поставок
const suppliesHistoryOptions = {
fetchPolicy: 'cache-and-network' as const,
pollInterval: 30000,
errorPolicy: 'all' as const,
}
// 1. Основные поставки (главная таблица)
useQuery(GET_MY_FULFILLMENT_SUPPLIES, suppliesHistoryOptions)
// 2. Детали поставок (раскрывающиеся строки)
useQuery(GET_MY_FULFILLMENT_CONSUMABLE_SUPPLIES, suppliesHistoryOptions)
🚨 КРИТИЧЕСКИЕ АНТИ-ПАТТЕРНЫ
❌ НИКОГДА НЕ ДЕЛАЙТЕ:
1. Разные fetchPolicy для связанных данных
// ❌ СОЗДАЁТ РАССИНХРОНИЗАЦИЮ
const warehouse = useQuery(GET_WAREHOUSE, { fetchPolicy: 'cache-and-network' })
const supplies = useQuery(GET_SUPPLIES, {}) // default cache-first
// Результат: warehouse показывает новые данные, supplies - старые
2. Разные pollInterval для одной функциональности
// ❌ СОЗДАЁТ НЕСОГЛАСОВАННОСТЬ
const stats = useQuery(GET_STATS, { pollInterval: 30000 })
const details = useQuery(GET_DETAILS, { pollInterval: 60000 })
// Результат: stats обновляется чаще details - значения не совпадают
3. Смешивание cache-first и cache-and-network
// ❌ КЛАССИЧЕСКАЯ ОШИБКА
const mainData = useQuery(MAIN_QUERY, { fetchPolicy: 'cache-and-network' })
const relatedData = useQuery(RELATED_QUERY, { fetchPolicy: 'cache-first' })
// Результат: mainData актуальные, relatedData устаревшие
4. Игнорирование ошибок в критических компонентах
// ❌ СКРЫВАЕТ ПРОБЛЕМЫ
useQuery(CRITICAL_DATA_QUERY, {
errorPolicy: 'ignore', // Не показывает ошибки когда нужно!
})
📊 ПРАВИЛА ПО ТИПАМ ДАННЫХ
СТАТИСТИКА И DASHBOARD
const dashboardOptions = {
fetchPolicy: 'cache-and-network', // Всегда актуальные данные
pollInterval: 30000, // 30 сек - критическая актуальность
errorPolicy: 'all', // Показывать частичные данные
notifyOnNetworkStatusChange: true, // Показывать индикатор обновления
}
ИНВЕНТАРЬ И ОСТАТКИ
const inventoryOptions = {
fetchPolicy: 'cache-and-network', // Остатки должны быть точными
pollInterval: 30000, // Частое обновление
errorPolicy: 'all', // Критические данные
}
ИСТОРИЯ И ЛОГИ
const historyOptions = {
fetchPolicy: 'cache-first', // История не меняется часто
pollInterval: 120000, // 2 минуты достаточно
errorPolicy: 'all', // Показывать что есть
}
СПРАВОЧНИКИ И КАТАЛОГИ
const catalogOptions = {
fetchPolicy: 'cache-first', // Справочники стабильны
pollInterval: 300000, // 5 минут
errorPolicy: 'ignore', // Не критично
}
🔧 ПРАКТИЧЕСКИЕ ПРИМЕРЫ ИСПРАВЛЕНИЙ
ПРИМЕР 1: Рассинхронизация карточек статистики
❌ Проблема:
// Главный dashboard
const warehouseStats = useQuery(GET_WAREHOUSE_STATS, {
fetchPolicy: 'cache-and-network',
})
// Подраздел supplies
const suppliesStats = useQuery(GET_SUPPLIES_STATS, {
// default fetchPolicy: 'cache-first' - ПРОБЛЕМА!
})
// Результат: карточка "РАСХОДНИКИ ФУЛФИЛМЕНТА" = 130, карточка "ОСТАТОК" = 160
✅ Решение:
// Общие настройки для всех статистических компонентов
const statsOptions = {
fetchPolicy: 'cache-and-network' as const,
pollInterval: 30000,
errorPolicy: 'all' as const,
}
// Применяем везде одинаково
const warehouseStats = useQuery(GET_WAREHOUSE_STATS, statsOptions)
const suppliesStats = useQuery(GET_SUPPLIES_STATS, statsOptions)
ПРИМЕР 2: История поставок не синхронизируется с основной таблицей
❌ Проблема:
// Основная таблица
const supplies = useQuery(GET_SUPPLIES, { fetchPolicy: 'cache-and-network' })
// История в раскрывающихся строках
const history = useQuery(GET_SUPPLY_HISTORY, {}) // default cache-first
// Результат: основная таблица обновилась, история показывает старые данные
✅ Решение:
const syncedOptions = {
fetchPolicy: 'cache-and-network',
pollInterval: 30000,
}
const supplies = useQuery(GET_SUPPLIES, syncedOptions)
const history = useQuery(GET_SUPPLY_HISTORY, syncedOptions)
🎯 ЧЕКЛИСТ НАСТРОЙКИ КЕШИРОВАНИЯ
Перед релизом компонента:
- Определили группу связанных компонентов
- Выбрали единую fetchPolicy для группы
- Установили одинаковые pollInterval значения
- Настроили errorPolicy в соответствии с критичностью
- Протестировали синхронизацию данных
При обнаружении рассинхронизации:
- Проверили fetchPolicy всех связанных запросов
- Сравнили pollInterval значения
- Убедились в использовании одних таблиц БД
- Проверили последовательность обновления данных
📈 МОНИТОРИНГ И ОТЛАДКА
DEBUG ЛОГИ ДЛЯ КЕШИРОВАНИЯ
// Добавляйте в компоненты для контроля кеширования
useQuery(QUERY, {
fetchPolicy: 'cache-and-network',
onCompleted: (data) => {
console.log('CACHE DEBUG:', {
query: 'QUERY_NAME',
timestamp: new Date().toISOString(),
dataLength: data?.items?.length,
source: 'network/cache',
})
},
onError: (error) => {
console.error('CACHE ERROR:', {
query: 'QUERY_NAME',
error: error.message,
networkError: error.networkError?.message,
})
},
})
ПРОВЕРКА СИНХРОНИЗАЦИИ
// Контрольные точки для проверки консистентности
useEffect(() => {
if (masterData && detailData) {
const masterValue = masterData.total
const detailValue = detailData.reduce((sum, item) => sum + item.value, 0)
if (Math.abs(masterValue - detailValue) > 0) {
console.error('🚨 CACHE SYNC ERROR:', {
component: 'ComponentName',
master: masterValue,
detail: detailValue,
diff: masterValue - detailValue,
})
}
}
}, [masterData, detailData])
🚀 РЕКОМЕНДАЦИИ ПО ПРОИЗВОДИТЕЛЬНОСТИ
ОПТИМИЗАЦИЯ POLLING
// Адаптивные интервалы в зависимости от активности пользователя
const useAdaptivePolling = () => {
const [isActive, setIsActive] = useState(true)
useEffect(() => {
const handleVisibilityChange = () => {
setIsActive(!document.hidden)
}
document.addEventListener('visibilitychange', handleVisibilityChange)
return () => document.removeEventListener('visibilitychange', handleVisibilityChange)
}, [])
return {
pollInterval: isActive ? 30000 : 120000, // Реже обновляем неактивные вкладки
}
}
УСЛОВНОЕ КЕШИРОВАНИЕ
// Разные стратегии для разных сценариев
const getCachePolicy = (dataType: string) => {
switch (dataType) {
case 'critical-stats':
return { fetchPolicy: 'cache-and-network', pollInterval: 30000 }
case 'user-lists':
return { fetchPolicy: 'cache-and-network', pollInterval: 60000 }
case 'reference-data':
return { fetchPolicy: 'cache-first', pollInterval: 300000 }
default:
return { fetchPolicy: 'cache-first' }
}
}
Следование этим правилам обеспечит стабильное кеширование и синхронизацию GraphQL данных! 🚀