React Architecture
React Architecture Notes
Section titled “React Architecture Notes”Scope: React viewer toolkit (@scaryterry/pdfium/react, @scaryterry/pdfium/react/headless, @scaryterry/pdfium/react/editor).
See Architecture Map for a concrete module-to-layer map. See Contributor Playbook for required file shapes and test gates.
Layering
Section titled “Layering”Keep React code split into clear layers:
src/headless/**- Framework-agnostic session, viewer, and editor ownership.
src/react/headless/**- Public React bindings over the headless ownership model.
src/react/components/**- Thin shipped-shell composition and public shell entry points.
src/react/internal/**- View-model helpers, rendering primitives, orchestration helpers, and panel-specific view/model logic.
src/react/hooks/**- React-facing state hooks, effects, and async lifecycle guards.
The key rule now is simple: shell behavior must not exist separately from headless behavior. Shipped shells compose the public headless surface; they do not own a second copy of the runtime.
Panel structure
Section titled “Panel structure”Preferred panel shape:
components/panels/<panel>.tsx- Thin export/wrapper only.
internal/<panel>-view.tsx- UI rendering and event wiring.
internal/<panel>-model.ts- Pure transformations, labels, and tab/state utilities.
This keeps JSX-heavy rendering isolated from pure model logic and simplifies race-focused unit tests.
Hook structure
Section titled “Hook structure”Preferred hook shape:
- Hook file coordinates refs/effects and public return shape.
- Pure computation goes in
internal/*-model.tsmodules. - Async guard behavior should rely on generation/request tokens instead of mutable booleans.
Examples in this repository:
use-visible-pages+internal/visible-pages-model.ts- provider lifecycle split across:
internal/use-pdfium-provider-controller.tsinternal/provider-*modules
Consistency rules
Section titled “Consistency rules”- Keep external store/cache operations centralized in internal modules (
query-store, lifecycle helpers). - Keep format/copy/table concerns in
internal/*-copy.tsand shared view primitives. - Minimize component-local side effects; prefer hook-level orchestration and explicit cleanup.
Review checklist for new React code
Section titled “Review checklist for new React code”- Is stale async completion ignored after dependency changes?
- Are subscriptions/listeners/timers always cleaned?
- Is pure logic separated from render wiring?
- Are tests covering success, failure, and stale-race paths?
See also
Section titled “See also”- Architecture Map - Concrete module-to-layer mapping.
- React Contributor Playbook - Required shapes for wrappers, views, hooks, and tests.
- React Testing - Validation standards for race safety and teardown discipline.