u/Ok_Market_5845

Open-sourced a React 18 media gallery app — TanStack Virtual, Zustand, shadcn/ui, and client-side ML

Open-sourced a React 18 media gallery app — TanStack Virtual, Zustand, shadcn/ui, and client-side ML

I've been building SubHarvest, a self-hosted Reddit media harvester, and just open-sourced it. The frontend has some patterns that might be useful to others so I wanted to share.

Frontend stack: React 18, Vite, TanStack Query, TanStack Virtual, Zustand, Tailwind CSS, Radix UI / shadcn/ui, Zod

Rendering 10k+ images without melting the browser

The main gallery uses TanStack Virtual for a masonry grid layout. Each card is measured and positioned dynamically. With virtualisation, scrolling through 10,000+ assets stays at 60fps because only visible items are in the DOM. Cursor-based pagination from the API means we never load the full dataset upfront.

Client-side NSFW detection

Instead of running ML on the server, we load TensorFlow.js + nsfwjs lazily in the browser via dynamic import(). The model only loads when the user enables enhanced NSFW scanning. Scores are computed client-side and PATCHed back to the API. The hook (useNsfwScanner) is a no-op when disabled — zero bundle cost.

State management split

  • Server state: TanStack Query handles all API data (assets, channels, sync jobs, collections). Query keys are structured so mutations invalidate the right caches.
  • Client state: Zustand for two small stores — auth (JWT tokens persisted to localStorage with auto-refresh on 401) and UI preferences (theme, view mode, NSFW filter toggle).
  • No Redux, no context providers for data fetching.

Shared types with the backend

The monorepo has a u/subharvest/types package with Zod schemas. The API validates requests with them, the frontend uses the inferred TypeScript types. One source of truth for the shape of every API response.

Other frontend patterns:

  • Command palette (Cmd+K) for global navigation
  • G-chord keyboard shortcuts (G then H for home, G then A for all assets)
  • Lightbox with keyboard nav, video controls, and metadata panel
  • Auto token refresh — the API client intercepts 401s, calls /auth/refresh, and retries the original request transparently
  • Filter bar state synced to URL params so gallery views are shareable/bookmarkable

Testing: 8 frontend tests covering the auth store (token parsing, persistence, clear) and the API client (auth headers, error handling, 401 refresh flow).

Repo: https://github.com/tamerUAE/AutoReddit

Feedback welcome — especially on the virtualisation approach or the auth flow.

u/Ok_Market_5845 — 11 hours ago