跪拜 Guibai
← All articles
React.js

A Model/API Layering Architecture for React and TypeScript Projects

By mONESY ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Scattered fetch calls and untyped props are the fastest way to turn a React codebase into a maintenance tax. A model/api/components split with strict TypeScript types removes guesswork from data flow and makes API changes a one-file operation, which pays off the moment a second developer joins or a backend contract changes.

Summary

A model/api/components layering scheme, demonstrated through a React color picker, treats TypeScript interfaces as the constitution for all frontend data. The model layer defines what data the UI needs—not what the backend happens to return—while the API layer wraps every endpoint behind a typed function so components never touch raw fetch calls or untyped responses. Components become pure consumers of typed props, with state lifted to a parent and updated through callbacks, producing a unidirectional data flow that is legible even as the project grows.

Concrete patterns include using an IIFE inside useEffect for async data loading, spreading old state for immutable updates in controlled components, and typing inline styles as React.CSSProperties to catch misspelled property names at compile time. The directory structure itself encodes the architecture: model/, api/, and components/ tell a new developer exactly where to find or place code.

The argument is that these habits are best internalized on small projects, where the overhead is negligible but the template becomes immediately reusable for larger work.

Takeaways
TypeScript interfaces in a dedicated model/ directory serve as the single source of truth for all frontend data shapes.
An API layer wraps every endpoint behind a typed function, keeping fetch calls and URL strings out of components entirely.
Controlled components receive state and an updater callback via props; they never own or directly mutate shared state.
Immutable state updates use the spread operator to copy the previous object before overwriting a specific field.
Async data fetching in useEffect uses an IIFE pattern because the effect callback itself cannot be async.
Typing inline styles as React.CSSProperties catches property-name typos at compile time rather than at runtime.
The directory structure—model/, api/, components/—acts as a self-documenting scaffold for where code belongs.
Conclusions

The model layer is defined by what the frontend needs, not by what the backend returns; the API layer is where any field-name mismatch gets resolved.

Passing a useState setter directly as a callback works cleanly when its signature matches the expected handler, eliminating wrapper functions.

Small projects are the ideal place to drill architectural habits because the overhead is trivial but the template becomes a reusable starting point for larger work.

Concepts & terms
Model/API/Components layering
A frontend architecture that separates TypeScript data interfaces (model/), typed API functions (api/), and UI components (components/) so that data shapes, network calls, and rendering concerns evolve independently.
Controlled component
A React component that does not hold its own state but receives its current value and a change handler via props, keeping the single source of truth in a parent.
IIFE in useEffect
An Immediately Invoked Function Expression used inside a useEffect callback to run async logic, since the effect callback itself cannot be declared async.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗