Skip to main content

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:

  1. Forms: While TanStack Form was installed, forms were using simple uncontrolled patterns without proper validation integration
  2. Data Fetching: Data fetching was handled manually with useEffect hooks, leading to boilerplate code for loading states, error handling, and caching
  3. 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:

  1. 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
  2. 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
  3. 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

  1. Improved Developer Experience

    • Declarative data fetching with automatic loading/error states
    • Type-safe forms with runtime validation
    • Reduced boilerplate code
  2. Better Performance

    • Intelligent caching reduces unnecessary API calls
    • Background refetching keeps data fresh
    • Optimistic updates for better perceived performance
  3. Enhanced User Experience

    • Real-time validation feedback
    • Faster page loads due to caching
    • Consistent loading and error states
  4. Maintainability

    • Clear separation between data fetching and UI logic
    • Centralized validation schemas
    • Predictable patterns across the application

Negative

  1. Learning Curve

    • Developers need to understand TanStack Query concepts (stale time, cache time, etc.)
    • More complex mental model compared to simple useEffect
  2. Bundle Size

    • Added ~50KB for TanStack Query (acceptable trade-off for the benefits)
  3. 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

Decision Makers

  • Development Team
  • Technical Lead
  • None (this is the first ADR)