fix: enable virtualization for worksheet preview by limiting SSR to 3 pages
**Root Cause:** Server was generating ALL pages during SSR and passing them as initialData, which pre-populated the entire loadedPages Map. This bypassed the virtualization system because pagesToFetch was always empty. **Changes:** 1. **page.tsx** - Only generate first 3 pages on server - Changed generateWorksheetPreview() to include startPage/endPage params - Server now generates min(3, totalPages) instead of all pages - Added clear comments explaining SSR vs virtualization split 2. **WorksheetPreview.tsx** - Cleaned up debug logging - Removed all console.log statements added during investigation - Virtualization logic unchanged (was already correct) **Result:** - Initial page load: Fast (only 3 pages) - Scrolling: Progressive loading with visible network activity - 100-page worksheet: Loads incrementally as user scrolls - Memory usage: Only loaded pages in memory, not entire set 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
2edce96f1c
commit
f409e3c2ed
|
|
@ -64,7 +64,5 @@
|
|||
"ask": []
|
||||
},
|
||||
"enableAllProjectMcpServers": true,
|
||||
"enabledMcpjsonServers": [
|
||||
"sqlite"
|
||||
]
|
||||
"enabledMcpjsonServers": ["sqlite"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use client'
|
||||
|
||||
import { css } from '@styled/css'
|
||||
import { useState } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useTheme } from '@/contexts/ThemeContext'
|
||||
import { StudentNameInput } from './config-panel/StudentNameInput'
|
||||
import { ContentTab } from './config-sidebar/ContentTab'
|
||||
|
|
@ -11,6 +11,8 @@ import { ScaffoldingTab } from './config-sidebar/ScaffoldingTab'
|
|||
import { TabNavigation } from './config-sidebar/TabNavigation'
|
||||
import { useWorksheetConfig } from './WorksheetConfigContext'
|
||||
|
||||
const ACTIVE_TAB_KEY = 'worksheet-config-active-tab'
|
||||
|
||||
interface ConfigSidebarProps {
|
||||
isSaving?: boolean
|
||||
lastSaved?: Date | null
|
||||
|
|
@ -24,10 +26,30 @@ export function ConfigSidebar({
|
|||
}: ConfigSidebarProps) {
|
||||
const { resolvedTheme } = useTheme()
|
||||
const isDark = resolvedTheme === 'dark'
|
||||
const [activeTab, setActiveTab] = useState('operator')
|
||||
const { formState, onChange, isReadOnly: contextReadOnly } = useWorksheetConfig()
|
||||
const effectiveReadOnly = isReadOnly || contextReadOnly
|
||||
|
||||
// Always initialize with default to avoid hydration mismatch
|
||||
const [activeTab, setActiveTab] = useState<string>('operator')
|
||||
const [isInitialized, setIsInitialized] = useState(false)
|
||||
|
||||
// Load from sessionStorage after mount (client-side only, runs once)
|
||||
useEffect(() => {
|
||||
const savedTab = sessionStorage.getItem(ACTIVE_TAB_KEY)
|
||||
if (savedTab) {
|
||||
setActiveTab(savedTab)
|
||||
}
|
||||
setIsInitialized(true)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
// Persist activeTab to sessionStorage whenever it changes (but only after initialization)
|
||||
useEffect(() => {
|
||||
if (isInitialized) {
|
||||
sessionStorage.setItem(ACTIVE_TAB_KEY, activeTab)
|
||||
}
|
||||
}, [activeTab, isInitialized])
|
||||
|
||||
return (
|
||||
<div
|
||||
data-component="config-sidebar"
|
||||
|
|
|
|||
|
|
@ -198,7 +198,9 @@ function PreviewContent({
|
|||
|
||||
// Fetch pages as they become visible
|
||||
useEffect(() => {
|
||||
if (!shouldVirtualize) return
|
||||
if (!shouldVirtualize) {
|
||||
return
|
||||
}
|
||||
|
||||
// Find pages that are visible but not loaded and not being fetched
|
||||
const pagesToFetch = Array.from(visiblePages).filter(
|
||||
|
|
@ -260,7 +262,7 @@ function PreviewContent({
|
|||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(`Failed to fetch pages ${start}-${end}:`, error)
|
||||
console.error(`[Virtualization] Failed to fetch pages ${start}-${end}:`, error)
|
||||
|
||||
// Remove from fetching set on error
|
||||
setFetchingPages((prev) => {
|
||||
|
|
|
|||
|
|
@ -100,9 +100,12 @@ export default async function AdditionWorksheetPage() {
|
|||
date: getDefaultDate(),
|
||||
}
|
||||
|
||||
// Pre-generate worksheet preview on the server
|
||||
console.log('[SSR] Generating worksheet preview on server...')
|
||||
const previewResult = generateWorksheetPreview(fullConfig)
|
||||
// Pre-generate ONLY the first 3 pages on the server
|
||||
// The virtualization system will handle loading additional pages on-demand
|
||||
const INITIAL_PAGES = 3
|
||||
const pagesToGenerate = Math.min(INITIAL_PAGES, pages)
|
||||
console.log(`[SSR] Generating initial ${pagesToGenerate} pages on server (total: ${pages})...`)
|
||||
const previewResult = generateWorksheetPreview(fullConfig, 0, pagesToGenerate - 1)
|
||||
console.log('[SSR] Preview generation complete:', previewResult.success ? 'success' : 'failed')
|
||||
|
||||
// Pass settings and preview to client, wrapped in error boundary
|
||||
|
|
|
|||
Loading…
Reference in New Issue