React + TanStack Senior Developer Skill
Core Philosophy
KISS > Clever Code
Readability > Brevity
Explicit > Implicit
Composition > Inheritance
Colocation > Separation
Type Safety > Any
Quick Decision Tree
State Management:
Server state → TanStack Query (WAJIB) URL state → TanStack Router search params Form state → TanStack Form atau React Hook Form Global UI state → Zustand (bukan Redux) Local UI state → useState/useReducer
Routing:
SPA → TanStack Router Full-stack SSR → TanStack Start Existing Next.js → tetap Next.js Project Setup Workflow
Determine project type:
SPA/Client-only? → Vite + TanStack Router + Query Full-stack SSR? → TanStack Start (Vinxi-based) Existing project? → Incremental adoption
Initialize project → See folder-structure.md
Setup core dependencies → See recommended-libraries.md
TanStack Ecosystem References Library When to Read tanstack-query.md Data fetching, caching, mutations tanstack-router.md Type-safe routing, loaders, search params tanstack-table.md Complex tables, sorting, filtering, pagination tanstack-form.md Form validation, field arrays, async validation tanstack-start.md Full-stack SSR framework Code Quality Standards Naming Conventions // Components: PascalCase dengan suffix deskriptif UserProfileCard.tsx // ✓ UserCard.tsx // ✗ terlalu generic user-profile.tsx // ✗ wrong case
// Hooks: camelCase dengan prefix 'use' useUserProfile() // ✓ useGetUserProfile() // ✗ redundant 'Get' getUserProfile() // ✗ missing 'use'
// Query keys: array dengan hierarchy
['users', 'list', { status }] // ✓
['usersList'] // ✗ tidak granular
users-${status} // ✗ string interpolation
// Files: kebab-case untuk non-components api-client.ts // ✓ apiClient.ts // ✗
Component Structure Pattern // 1. Imports (grouped: external → internal → types) import { useSuspenseQuery } from '@tanstack/react-query' import { userQueries } from '@/features/users/api' import type { User } from '@/features/users/types'
// 2. Types (colocated, tidak di file terpisah kecuali shared) interface UserCardProps { userId: string onSelect?: (user: User) => void }
// 3. Component (single responsibility) export function UserCard({ userId, onSelect }: UserCardProps) { // 3a. Queries/mutations first const { data: user } = useSuspenseQuery(userQueries.detail(userId))
// 3b. Derived state (useMemo hanya jika expensive)
const fullName = ${user.firstName} ${user.lastName}
// 3c. Handlers (useCallback hanya jika passed to memoized children) const handleClick = () => onSelect?.(user)
// 3d. Early returns untuk edge cases if (!user.isActive) return null
// 3e. JSX (clean, minimal nesting)
return (
{user.email}{fullName}
Anti-Patterns to AVOID // ❌ NEVER: useEffect untuk data fetching useEffect(() => { fetch('/api/users').then(setUsers) }, [])
// ✅ ALWAYS: TanStack Query const { data: users } = useQuery(userQueries.list())
// ❌ NEVER: Prop drilling lebih dari 2 level
// ✅ ALWAYS: Context atau query di level yang butuh function GrandChild() { const { data: user } = useQuery(userQueries.current()) }
// ❌ NEVER: Premature optimization const value = useMemo(() => a + b, [a, b]) // simple math
// ✅ ALWAYS: Optimize only when measured const value = a + b // just calculate
// ❌ NEVER: Index as key untuk dynamic lists
// ✅ ALWAYS: Stable unique identifier
Debugging Guide
See debugging-guide.md for:
React DevTools profiling TanStack Query DevTools Memory leak detection Performance bottleneck identification Common error patterns Common Pitfalls & Bugs
See common-pitfalls.md for:
Stale closure bugs Race conditions Memory leaks patterns Hydration mismatches Query invalidation mistakes Performance Checklist □ Bundle size < 200KB gzipped (initial) □ Largest Contentful Paint < 2.5s □ No unnecessary re-renders (React DevTools) □ Images lazy loaded □ Code splitting per route □ Query deduplication working □ No memory leaks (heap snapshot stable)
Code Review Checklist
□ No any types (use unknown if needed)
□ No // @ts-ignore tanpa penjelasan
□ Error boundaries di route level
□ Loading states handled
□ Empty states handled
□ Error states handled
□ Accessibility (aria labels, keyboard nav)
□ No hardcoded strings (i18n ready)
□ No console.log in production code
□ Tests untuk business logic