State Integration Patterns
Common patterns for integrating server and client state in React Native applications
State Integration Patterns
Overview
This document outlines architectural patterns for effectively integrating different types of state management in React Native applications. It focuses on the coordination between server state (TanStack Query), client state (Zustand), and component state (React), providing solutions for common state integration challenges while maintaining a clean separation of concerns.
Purpose & Scope
- Target Audience: React Native developers implementing features that require coordination between multiple state management approaches
- Problems Addressed: Complex state interactions, synchronization challenges, and maintaining data consistency
- Scope: Covers integration patterns specifically for authentication flows, shopping carts, forms with drafts, real-time updates, and filter/search functionality
Authentication Flow Pattern
A complete authentication flow demonstrates how to coordinate between different state types:
Shopping Cart with Sync Pattern
Managing a shopping cart that syncs with the server:
Form with Draft Saving Pattern
Complex form with local state and server persistence:
Real-time Updates with Polling Pattern
Combining server polling with optimistic client updates:
Filter and Search State Pattern
Managing complex filter state with server queries:
Core Components/Architecture
The integration patterns involve these key components working together:
Component Types
| Component | Responsibility | Common Patterns |
|---|---|---|
| Component State | UI interactions, form inputs, temporary data | Form handling, UI element state, local interactions |
| Zustand Store | Application-wide client state, persistent preferences | Auth state, preferences, cart data, offline support |
| TanStack Query | Server data fetching, caching, synchronization | API responses, optimistic updates, background polling |
| Integration Layer | Coordinating data flow between state types | Event handlers, useEffect hooks, side effects |
Communication Patterns
- Component → Zustand: Direct state updates via store actions
- Component → TanStack Query: Query invalidation, cache manipulation
- Zustand → TanStack Query: Query enablement, dependent queries
- TanStack Query → API: Data fetching, mutations with optimistic updates
Design Principles
Core Architectural Principles
-
(Do ✅) Establish clear ownership for each piece of state:
- Server data → TanStack Query
- UI state → Zustand or Component State
- Form data → Component State until submission
-
(Don't ❌) Store server data in client state unnecessarily:
- Avoid duplication between TanStack Query cache and Zustand
- Reference server data directly in components when possible
-
(Do ✅) Implement optimistic updates for better UX:
- Update UI immediately for responsive feedback
- Sync with server in background
- Handle failures gracefully with rollback mechanisms
Trade-offs and Decisions
| Approach | Benefits | Drawbacks | Best For |
|---|---|---|---|
| Minimal state integration | Simpler mental model, clearer boundaries | May lead to prop drilling, more boilerplate | Simple screens, isolated features |
| Tightly coupled state | Fewer lines of code, direct coordination | Harder to debug, potential circular dependencies | Complex interactions, real-time features |
| Event-based coordination | Loose coupling, easier to test | More complex initial setup | Large teams, complex state flows |
Implementation Considerations
Performance Implications
- (Do ✅) Use selective Zustand subscriptions to prevent unnecessary renders
- (Consider 🤔) Configuring TanStack Query with appropriate staleTime/gcTime settings based on data volatility
- (Do ✅) Apply React memoization techniques (memo, useMemo, useCallback) at integration boundaries
- (Be Aware ❗) Integration points between state systems are common sources of render loops
Security Considerations
- (Do ✅) Never store sensitive information (tokens, PII) in unencrypted client state
- (Do ✅) Apply appropriate validation at both client and server boundaries
- (Don't ❌) Trust client state for security decisions - always validate permissions on the server
Scalability Aspects
- (Consider 🤔) Breaking large state stores into smaller, feature-focused ones
- (Do ✅) Design query key factories for consistent cache manipulation
- (Be Aware ❗) Complex state interactions may require dedicated middleware or effect systems
Common Integration Patterns
The following sections detail specific integration patterns for common scenarios. Each pattern demonstrates how to effectively coordinate between different state management systems.