Skip to content

fix: window syllabus grid rows and drop eager prefetch#466

Draft
posthog-eu[bot] wants to merge 2 commits into
devfrom
posthog-code/syllabus-grid-windowing
Draft

fix: window syllabus grid rows and drop eager prefetch#466
posthog-eu[bot] wants to merge 2 commits into
devfrom
posthog-code/syllabus-grid-windowing

Conversation

@posthog-eu

@posthog-eu posthog-eu Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

The Syllabus Repository (/syllabus) rendered the entire catalog in one pass — getAllSyllabi() returns every row and SyllabusGrid rendered each as a Next <Link prefetch>. On large catalogs that combines mass route prefetching with a heavy hydration/render pass that blocks the main thread, so taps on rows stay unresponsive for tens of seconds (surfacing as rage-clicks) before navigation finally happens. There were no thrown exceptions — this is a performance/UX problem.

This PR keeps the instant client-side search intact while cutting the main-thread work:

  • Window the rendered rows — only 48 rows render initially, revealing more via an IntersectionObserver sentinel as the user scrolls. The window resets on search; filtering still runs over the full list.
  • Drop eager per-row prefetchprefetch={false} plus hover/focus router.prefetch, matching the existing pattern in course-search.tsx, so we no longer fire prefetches for the whole catalog on load.
  • Memoize SyllabusRow so selection changes only re-render the affected rows.

Why

Two independent session recordings on the /syllabus browse flow showed repeated rage-clicks and dozens of rapid dead clicks on syllabus rows, with navigation only succeeding 20–90s later — a repeatable degradation of a core content-discovery flow.

Verification

tsc --noEmit passes on the changed file (remaining errors are pre-existing, repo-wide missing generated .svg/.json type declarations produced by next dev). A live before/after could not be reproduced in the sandbox — no PostgreSQL server binary and no build/OAuth setup available — so this was not exercised against a running instance; the change directly targets the two root causes identified from the session recordings.


Created with PostHog Code from an inbox report.

spent a lot of water and tokens to review your slop

Greptile Summary

This PR reduces initial work in the syllabus catalog. The main changes are:

  • Renders syllabus rows in batches as the user scrolls.
  • Resets the visible window when the search query changes.
  • Disables eager link prefetching and prefetches on hover or focus.
  • Memoizes individual syllabus rows.
  • Adds a fallback for browsers without IntersectionObserver.

Confidence Score: 5/5

This looks safe to merge.

The search window now resets before the updated results commit. Browsers without IntersectionObserver no longer crash or leave the catalog truncated.

No blocking issues remain in the changed code.

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex loaded the SyllabusGrid UI and launched the Playwright harness against the synthetic component page.
  • T-Rex captured the initial rendered UI image showing a 48-row bounded window.
  • T-Rex ran the runtime harness and inspected logs, which recorded the successful 48-link render followed by environment failures.
  • T-Rex documented the available artifacts (image, logs, and source files) to help reviewers inspect the proof conditions.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
app/components/syllabus/syllabus-grid.tsx Adds windowed row rendering, search-window reset, on-demand route prefetching, row memoization, and an observer fallback.

Reviews (2): Last reviewed commit: "fix: reset syllabus window during render..." | Re-trigger Greptile

The /syllabus page renders the entire catalog at once, with every row as a
Next <Link prefetch>. On large catalogs that means mass route prefetching plus
a heavy hydration/render pass that blocks the main thread, so taps on rows go
unanswered for tens of seconds (observed as rage-clicks) before navigation
finally kicks in.

- Render only a window of the result set (48 rows, revealing more via an
  IntersectionObserver sentinel) so the main thread isn't blocked hydrating
  thousands of rows. The window resets on search; client-side filtering still
  runs over the full list.
- Drop eager per-row prefetch (prefetch={false}) and prefetch on hover/focus
  via router.prefetch instead, matching the pattern used in course-search.
- Memoize SyllabusRow so selection changes only re-render affected rows.

Generated-By: PostHog Code
Task-Id: b4f39c01-0934-4475-9755-209bd5eccbc8
@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
examcooker-dev Error Error Jul 13, 2026 4:21pm

Comment thread app/components/syllabus/syllabus-grid.tsx Outdated
Comment thread app/components/syllabus/syllabus-grid.tsx
Addresses two Greptile review findings:

- Reset visibleCount synchronously during render (via a tracked previous-query
  state) instead of in an effect, so a new search never commits with a stale,
  large window that would briefly mount hundreds of rows.
- Fall back to rendering all rows when IntersectionObserver is unavailable
  (older embedded WebViews) rather than throwing and leaving the catalog
  truncated at the initial window.

Generated-By: PostHog Code
Task-Id: b4f39c01-0934-4475-9755-209bd5eccbc8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants