Source:
ocean/docs/adr/0001-adopt-tanstack-ecosystem.md| ✏️ Edit on GitHub
ADR-0001: Adopt TanStack Ecosystem for Forms and Data Fetching
Date: 2025-01-26
Status
Accepted
Context
Our application was built with a solid foundation using TanStack Router, TanStack Form, and TanStack Table. However, we were not fully leveraging the capabilities of these libraries:
- Forms: While TanStack Form was installed, forms were using simple uncontrolled patterns without proper validation integration
- Data Fetching: Data fetching was handled manually with
useEffecthooks, leading to boilerplate code for loading states, error handling, and caching - Tables: TanStack Table was used for UI state management but lacked integration with a proper data fetching solution
A code audit revealed opportunities to better leverage our existing technology choices and improve the developer experience.
Decision
We will fully adopt the TanStack ecosystem by:
-
TanStack Form with Zod Validation
- Use TanStack Form for all forms with Zod schema validation
- Create centralized validation schemas
- Leverage built-in form state management
-
TanStack Query for Data Fetching
- Adopt TanStack Query for all server state management
- Create reusable query hooks for Supabase operations
- Implement proper caching and background refetching strategies
-
Integration Pattern
- TanStack Query fetches data → feeds into TanStack Table
- TanStack Form manages form state → validated with Zod → submitted via TanStack Query mutations
Consequences
Positive
-
Improved Developer Experience
- Declarative data fetching with automatic loading/error states
- Type-safe forms with runtime validation
- Reduced boilerplate code
-
Better Performance
- Intelligent caching reduces unnecessary API calls
- Background refetching keeps data fresh
- Optimistic updates for better perceived performance
-
Enhanced User Experience
- Real-time validation feedback
- Faster page loads due to caching
- Consistent loading and error states
-
Maintainability
- Clear separation between data fetching and UI logic
- Centralized validation schemas
- Predictable patterns across the application
Negative
-
Learning Curve
- Developers need to understand TanStack Query concepts (stale time, cache time, etc.)
- More complex mental model compared to simple
useEffect
-
Bundle Size
- Added ~50KB for TanStack Query (acceptable trade-off for the benefits)
-
Migration Effort
- Existing components need refactoring
- Testing strategies need updates
Implementation Details
Forms Example
// Before
const [email, setEmail] = useState('')
const [error, setError] = useState('')
// After
const form = useForm({
defaultValues: { email: '' },
validators: {
onChange: (value) => {
const result = loginSchema.shape.email.safeParse(value)
return result.success ? undefined : result.error.issues[0].message
},
},
})
Data Fetching Example
// Before
const [data, setData] = useState([])
const [loading, setLoading] = useState(true)
useEffect(() => {
fetchData()
.then(setData)
.finally(() => setLoading(false))
}, [])
// After
const { data, isLoading } = useQuery({
queryKey: ['dashboard', 'documents'],
queryFn: fetchData,
})
References
- TanStack Query Documentation
- TanStack Form Documentation
- Zod Documentation
- Original audit feedback that prompted this change
Decision Makers
- Development Team
- Technical Lead
Related ADRs
- None (this is the first ADR)