Separate Logic from UI with React Query and Custom Hooks

I've seen 100+ React codebases. The ones that scale? They all share ONE thing in common. Their components are dumb. Beautifully, embarrassingly dumb. Here's what most developers get wrong: They dump everything into one component — fetching, loading states, error handling, business logic, AND the UI. It works on day 1. By month 3, nobody wants to touch it. The fix? Brutal separation of logic and presentation. Here's the pattern that changed how I build: ───────────────────────── ❌ THE MESSY WAY (what 80% of teams ship) function UserProfile({ id }) { const [user, setUser] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) useEffect(() => { fetch(`/api/users/${id}`) .then(res => res.json()) .then(data => { setUser(data); setLoading(false) }) .catch(err => { setError(err); setLoading(false) }) }, [id]) if (loading) return <Spinner /> if (error) return <ErrorBanner /> return <div>...</div> // UI buried under logic } This is a ticking time bomb. Add caching? Retry logic? Stale-while-revalidate? This component explodes. ───────────────────────── ✅ THE CLEAN WAY (production-ready) LAYER 1 → API (pure function, zero React) // api/users.ts export const fetchUser = (id) => fetch(`/api/users/${id}`).then(res => res.json()) LAYER 2 → Custom Hook (logic lives here) // hooks/useUser.ts export function useUser(id) { return useQuery({ queryKey: ['user', id], queryFn: () => fetchUser(id), staleTime: 5 * 60 * 1000, }) } LAYER 3 → Component (pure presentation) // components/UserProfile.tsx export function UserProfile({ id }) { const { data, isLoading, error } = useUser(id) if (isLoading) return <Skeleton /> if (error) return <ErrorBanner /> return <div>{data.name}</div> } ───────────────────────── See what happened? → The component doesn't KNOW how data is fetched → Swap React Query for SWR tomorrow? Zero UI changes → Want to reuse this data on 3 other pages? useUser(id) — done → Testing? Each layer is independently testable This isn't theory. This is how teams at scale actually survive. The rules I live by: 1️⃣ If your component has more than 2 hooks, extract logic into a custom hook 2️⃣ API calls never live inside components 3️⃣ Components should only know about loading, data, and error — nothing else 4️⃣ Custom hooks are your business logic boundary React Query + Custom Hooks isn't just a pattern. It's the difference between code you maintain and code you rewrite. Start separating. Your future self will thank you. #React #ReactQuery #CleanCode #WebDevelopment #Frontend #JavaScript #SoftwareEngineering #TechLeadership #DevOps #CareerGrowth

To view or add a comment, sign in

Explore content categories