refactor: replace two-query system with single all-pages query

Replace pagination query system with single query that loads all pages:
- Remove INITIAL_PAGES constant and initial batch query
- Remove baseQueryKey constant (inline query key instead)
- Add initialDataUsed ref to only use SSR initial data once
- Change to single useSuspenseQuery that fetches all pages upfront
- Initialize loadedPages with all fetched pages immediately
- Simplify reset effect to only depend on pages array

This loads all pages in a single request instead of fetching initial
batch + on-demand fetching of remaining pages.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock 2025-11-17 10:46:41 -06:00
parent 7e3d84b127
commit fbb035b12b
1 changed files with 54 additions and 64 deletions

View File

@ -69,63 +69,64 @@ function PreviewContent({
const isDark = resolvedTheme === 'dark'
const pageRefs = useRef<(HTMLDivElement | null)[]>([])
// Common query key for all page-related queries
const baseQueryKey = [
'worksheet-preview',
// PRIMARY state
formState.problemsPerPage,
formState.cols,
formState.pages,
formState.orientation,
// V4: Problem size (CRITICAL - affects column layout and problem generation)
formState.digitRange?.min,
formState.digitRange?.max,
// V4: Operator selection (addition, subtraction, or mixed)
formState.operator,
// V4: Mode and conditional display settings
formState.mode,
formState.displayRules, // Smart mode: conditional scaffolding
formState.difficultyProfile, // Smart mode: difficulty preset
formState.manualPreset, // Manual mode: manual preset
// Mastery mode: skill IDs (CRITICAL for mastery+mixed mode)
formState.currentAdditionSkillId,
formState.currentSubtractionSkillId,
formState.currentStepId,
// Other settings that affect appearance
formState.name,
formState.pAnyStart,
formState.pAllStart,
formState.interpolate,
formState.showCarryBoxes,
formState.showAnswerBoxes,
formState.showPlaceValueColors,
formState.showProblemNumbers,
formState.showCellBorder,
formState.showTenFrames,
formState.showTenFramesForAll,
formState.seed, // Include seed to bust cache when problem set regenerates
// Note: fontSize, date, rows, total intentionally excluded
// (rows and total are derived from primary state)
] as const
// Track if we've used the initial data (so we only use it once)
const initialDataUsed = useRef(false)
// Fetch initial batch to get total page count and first few pages
const INITIAL_PAGES = 3
const { data: initialResponse } = useSuspenseQuery({
queryKey: [...baseQueryKey, 'initial'],
// Only use initialData on the very first query, not on subsequent fetches
const queryInitialData = !initialDataUsed.current && initialData ? initialData : undefined
if (queryInitialData) {
initialDataUsed.current = true
}
// Use Suspense Query - will suspend during loading
const { data: pages } = useSuspenseQuery({
queryKey: [
'worksheet-preview',
// PRIMARY state
formState.problemsPerPage,
formState.cols,
formState.pages,
formState.orientation,
// V4: Problem size (CRITICAL - affects column layout and problem generation)
formState.digitRange?.min,
formState.digitRange?.max,
// V4: Operator selection (addition, subtraction, or mixed)
formState.operator,
// V4: Mode and conditional display settings
formState.mode,
formState.displayRules, // Smart mode: conditional scaffolding
formState.difficultyProfile, // Smart mode: difficulty preset
formState.manualPreset, // Manual mode: manual preset
// Mastery mode: skill IDs (CRITICAL for mastery+mixed mode)
formState.currentAdditionSkillId,
formState.currentSubtractionSkillId,
formState.currentStepId,
// Other settings that affect appearance
formState.name,
formState.pAnyStart,
formState.pAllStart,
formState.interpolate,
formState.showCarryBoxes,
formState.showAnswerBoxes,
formState.showPlaceValueColors,
formState.showProblemNumbers,
formState.showCellBorder,
formState.showTenFrames,
formState.showTenFramesForAll,
formState.seed, // Include seed to bust cache when problem set regenerates
// Note: fontSize, date, rows, total intentionally excluded
// (rows and total are derived from primary state)
],
queryFn: () => fetchWorksheetPreview(formState),
initialData: queryInitialData, // Only use on first render
})
const totalPages = initialResponse.length
const totalPages = pages.length
const [loadedPages, setLoadedPages] = useState<Map<number, string>>(() => {
// Initialize with initial pages or initialData
// Initialize with all pages
const map = new Map<number, string>()
if (initialData) {
initialData.forEach((page, index) => map.set(index, page))
} else {
initialResponse.forEach((page, index) => {
map.set(index, page)
})
}
pages.forEach((page, index) => map.set(index, page))
return map
})
@ -144,25 +145,14 @@ function PreviewContent({
// Track when refs are fully populated
const [refsReady, setRefsReady] = useState(false)
// Reset state when form config changes
// Reset to first page when preview updates
useEffect(() => {
setCurrentPage(0)
setVisiblePages(new Set([0]))
setFetchingPages(new Set())
pageRefs.current = []
setRefsReady(false)
// Reset loaded pages with new initial response
const map = new Map<number, string>()
if (initialData) {
initialData.forEach((page, index) => map.set(index, page))
} else {
initialResponse.forEach((page, index) => {
map.set(index, page)
})
}
setLoadedPages(map)
}, [initialResponse, initialData])
}, [pages])
// Fetch pages as they become visible
useEffect(() => {