Front-end Engineering Lab
RADIO Framework

(D) Data Model

Data flow, state management, caching, and data synchronization patterns

The Data Model phase defines how data flows through your system, how it's stored, cached, and synchronized. This is where you make decisions about state management, data fetching, and persistence.

Why Data Model Matters

Good data modeling:

  • Reduces redundant requests - Efficient caching and deduplication
  • Improves UX - Fast, responsive interfaces
  • Handles edge cases - Offline, sync, conflicts
  • Scales efficiently - Optimized data flow

Key Data Model Decisions

1. Data Fetching Strategies

When to use each pattern:

Fetch-on-Render:

  • Simple apps
  • No caching needed
  • Low traffic

Fetch-Then-Render:

  • Parallel requests
  • Better than sequential
  • Still blocks on data

Render-as-You-Fetch:

  • Progressive loading
  • Best UX
  • Complex implementation

Relevant Content:

Decision Framework:

Use Fetch-on-Render if:
✅ Simple app
✅ No caching needed
✅ Low traffic

Use Fetch-Then-Render if:
✅ Parallel requests needed
✅ Better than sequential
✅ Can wait for all data

Use Render-as-You-Fetch if:
✅ Progressive loading
✅ Best UX required
✅ Complex app

2. State Management

Global State Patterns:

Flux Architecture (Redux):

  • Complex global state
  • Time-travel debugging
  • Predictable updates
  • Large teams

Atom-Based State (Recoil, Jotai):

  • Fine-grained reactivity
  • Component-level state
  • Performance optimization
  • Simpler mental model

Signals:

  • Maximum performance
  • Fine-grained updates
  • Reactive primitives

State Machines (XState):

  • Complex workflows
  • UI state machines
  • Predictable transitions

Relevant Content:

Decision Framework:

Use Redux if:
✅ Complex global state
✅ Need debugging tools
✅ Large team

Use Recoil/Jotai if:
✅ Fine-grained reactivity
✅ Component-level state
✅ Simpler mental model

Use Signals if:
✅ Maximum performance
✅ Fine-grained updates

Use XState if:
✅ Complex workflows
✅ UI state machines

3. State Persistence

When to persist:

  • User preferences
  • Form drafts
  • Offline data
  • Cache data

Storage Options:

LocalStorage:

  • Simple key-value
  • Synchronous API
  • 5-10MB limit
  • String only

IndexedDB:

  • Complex data structures
  • Large storage (GBs)
  • Asynchronous API
  • Structured data

SessionStorage:

  • Tab-scoped
  • Cleared on close
  • Similar to LocalStorage

Relevant Content:

Decision Framework:

Use LocalStorage if:
✅ Simple key-value
✅ Small data (< 5MB)
✅ String data

Use IndexedDB if:
✅ Complex structures
✅ Large data (GBs)
✅ Structured data
✅ Async operations

4. State Synchronization

Cross-Tab Synchronization:

BroadcastChannel API:

  • Simple cross-tab communication
  • Browser-native
  • Limited browser support

Storage Events:

  • Listen to storage changes
  • Cross-tab sync
  • LocalStorage/SessionStorage only

Shared Web Workers:

  • Complex synchronization
  • Background processing
  • Advanced use cases

Relevant Content:

Decision Framework:

Use BroadcastChannel if:
✅ Simple sync needed
✅ Modern browsers
✅ Cross-tab communication

Use Storage Events if:
✅ LocalStorage sync
✅ Simple use cases
✅ Wide browser support

5. Optimistic Updates

When to use:

  • Instant feedback needed
  • Network latency high
  • User actions (likes, follows)
  • Non-critical operations

Pattern:

  1. Update UI immediately
  2. Send request to server
  3. Replace with server response
  4. Rollback on error

Relevant Content:

Decision Framework:

Use Optimistic Updates if:
✅ Instant feedback needed
✅ Non-critical operations
✅ Can rollback on error
✅ Good UX improvement

Avoid if:
❌ Critical operations (payments)
❌ Complex rollback logic
❌ Data consistency critical

6. Undo/Redo

When to use:

  • User actions need reversal
  • Complex workflows
  • Document editing
  • Form interactions

Relevant Content:

Decision Framework:

Use Undo/Redo if:
✅ User actions reversible
✅ Complex workflows
✅ Document editing
✅ Form interactions

7. Caching Strategies

Cache Patterns:

Memory Cache:

  • Fast access
  • Limited size
  • Lost on refresh

SWR (Stale-While-Revalidate):

  • Show cached, update in background
  • Great UX
  • Automatic revalidation

React Query:

  • Powerful caching
  • Request deduplication
  • Background updates
  • Optimistic updates

Normalized Cache:

  • Single source of truth
  • No duplication
  • Complex relationships

Relevant Content:

Decision Framework:

Use Memory Cache if:
✅ Simple caching
✅ Small data
✅ Fast access needed

Use SWR if:
✅ Stale-while-revalidate
✅ Automatic revalidation
✅ Great UX

Use React Query if:
✅ Powerful caching
✅ Request deduplication
✅ Background updates

Use Normalized Cache if:
✅ Complex relationships
✅ Single source of truth
✅ No duplication

8. File Handling

File Operations:

Upload:

  • Chunked uploads
  • Progress tracking
  • Resume capability
  • Error handling

Download:

  • Streaming downloads
  • Progress tracking
  • Large files

Processing:

  • Image compression
  • File hashing
  • Preview generation

Relevant Content:

Decision Framework:

Use Chunked Upload if:
✅ Large files (> 10MB)
✅ Resume capability
✅ Progress tracking

Use Streaming if:
✅ Large downloads
✅ Memory efficient
✅ Progress tracking

Data Model Checklist

Use this checklist when designing data flow:

Data Fetching

  • Fetching strategy chosen
  • Caching strategy defined
  • Request deduplication implemented
  • Error handling defined

State Management

  • State management pattern chosen
  • Global vs local state defined
  • State persistence strategy
  • State synchronization strategy

Caching

  • Cache strategy chosen
  • Cache invalidation defined
  • Cache size limits
  • Cache persistence

Optimistic Updates

  • Optimistic updates needed?
  • Rollback strategy defined
  • Error handling

Persistence

  • Persistence strategy chosen
  • Storage mechanism (LocalStorage/IndexedDB)
  • Data migration strategy
  • Cleanup strategy

Synchronization

  • Cross-tab sync needed?
  • Sync strategy chosen
  • Conflict resolution

Common Patterns

Simple App

Data Model:
- Fetch-on-render
- Local state only
- No persistence
- Basic error handling

Medium App

Data Model:
- React Query/SWR
- Global state (Redux/Recoil)
- LocalStorage persistence
- Optimistic updates
- Cross-tab sync

Complex App

Data Model:
- Render-as-you-fetch
- Normalized cache
- Complex state management
- IndexedDB persistence
- Advanced sync
- Undo/redo

Trade-offs

Redux vs Recoil

Redux:

  • ✅ Predictable
  • ✅ Time-travel debugging
  • ✅ Large ecosystem
  • ❌ Boilerplate
  • ❌ Learning curve

Recoil:

  • ✅ Fine-grained reactivity
  • ✅ Simpler mental model
  • ✅ Better performance
  • ❌ Smaller ecosystem
  • ❌ Newer technology

SWR vs React Query

SWR:

  • ✅ Simpler API
  • ✅ Smaller bundle
  • ✅ Vercel-backed
  • ❌ Less features

React Query:

  • ✅ More features
  • ✅ Better TypeScript
  • ✅ More control
  • ❌ Larger bundle

LocalStorage vs IndexedDB

LocalStorage:

  • ✅ Simple API
  • ✅ Synchronous
  • ✅ Wide support
  • ❌ Size limit
  • ❌ String only

IndexedDB:

  • ✅ Large storage
  • ✅ Structured data
  • ✅ Async operations
  • ❌ Complex API
  • ❌ Browser support

Next Steps

After defining data model, move to:

Remember: Good data modeling is invisible to users—they just see fast, responsive interfaces.

On this page