View all posts
Tutorials

Scalable Frontend Architecture: My Mental Framework using React and TypeScript

Proven techniques to structure massive SPAs: robust custom hooks, context separation, state injection, and B2B clean code.

Published on
Scalable Frontend Architecture: My Mental Framework using React and TypeScript

Throughout years of building robust platforms (Dashboards, internal CRMs, and E-commerces as a Full-Stack developer), the biggest difference between toy code and enterprise code is the level of maintainability.

React dominates frontend development, but it is notoriously unopinionated regarding structure. Today I want to share how I build the skeleton of a scalable SPA (Single Page Application).

1. Separation of Concerns using Custom Hooks

Components with thousands of lines of code, mixing fetch calls with HTML markup (<div/>), become unmanageable in the medium term.

In serious projects, my first rule is the separation of layers:

  • The UI Component only renders styles and interfaces.
  • Business Logic resides separately in Service Functions (Handlers, Utils).
  • Custom Hooks act as orchestrators.
// Bad Example (mixed)
function Dashboard() {
  const [data, setData] = useState(null)
  useEffect(() => { fetch('/api/data').then(...) }, [])
  return <div>{data?.name}</div>
}

// Good Example (orchestrated)
function Dashboard() {
  const { data, isLoading, error } = useDashboardMetrics()
  if (isLoading) return <Spinner />
  return <MetricsGrid renderData={data} />
}

2. Strict Typing (End-to-End TypeScript)

“Half-hearted” typing is useless. Using any eliminates the fundamental advantage of the TypeScript ecosystem. I recommend automatically generating interfaces based on the backend (e.g., using tRPC or OpenAPI generators) ensuring that if the database changes a model, our frontend will react by throwing a compile-time error, not in the client’s terminal during a traffic spike.

3. State Management: When NOT to use Context

There are countless tools out there (Redux, Zustand, Context). But many make the mistake of stuffing server state into client state managers. Golden Rule:

  • For asynchronous state (fetching, database cache): Use React Query or SWR.
  • For ephemeral Interface state (open menu, dark theme): Zustand or simple Context.

Adopting these 3 basic principles of cleanliness, business/UI separation, and intelligent orchestration ensures that when the B2B team needs to scale your application from 5 to 50 developers, the architecture won’t collapse.