Mostly about building products, healthcare tech, and lessons learned along the way.
Loading articles
React Tooling 2024: Stop Using the Wrong Shit | Clint Johnson
React Tooling 2024: Stop Using the Wrong Shit
The React ecosystem in 2024: 90% noise, 10% signal
I'm tired of "React best practices" articles written by people who've built three todo apps.
Here's what I actually use after shipping React to millions of users this year. More importantly: what I stopped using and why.
Routing: Just Use Next.js Already
The Only Three Options That Matter
1. Next.js App Router ✅
Stop debating. If you're starting a new project in 2024, use Next.js 14 with App Router. Yes, even for "SPAs."
Why? Because:
Server Components actually work now
Built-in data fetching that doesn't suck
Route-based code splitting for free
SEO without the PhD
// This is all you need. No setup. No config hell.// app/products/[id]/page.tsxexportdefaultasyncfunctionProduct({ params }){const product =awaitgetProduct(params.id)return<ProductView product={product}/>}
2. Tanstack Router 🤔
Only if you absolutely can't use Next.js. It's what React Router should have been. Type-safe routes, built-in search params handling, actually good.
I help teams ship AI in production — audits, consulting, custom agents, and eval systems. Start with an AI Audit (from $5k) for an honest read on what to build.
Legacy projects only. v6 broke everything good about v5. The docs still suck. Loader patterns are half-baked.
I migrated three apps away from React Router this year. Zero regrets.
Stop Calling React Query a Router
React Query (TanStack Query) isn't routing. It's data fetching. Different problem. Great library, wrong category.
State Management: You Probably Don't Need Redux
The Real Hierarchy (Use in This Order)
1. useState + Context 🎯
You don't need a library for state management. You need to learn React.
// This handles 80% of "state management" needsconstThemeContext=createContext()constCartContext=createContext()constUserContext=createContext()// That's it. You're done.
2. Zustand ✅
When Context gets messy (around 3-4 contexts), use Zustand. Not before.
// Entire store in 10 linesconst useStore =create((set)=>({user:null,cart:[],setUser:(user)=>set({ user }),addToCart:(item)=>set((state)=>({cart:[...state.cart, item]})),}))
No providers. No boilerplate. No DevTools extension breaking your Chrome.
3. Redux Toolkit 😔
Only if:
You have complex async flows
Time-travel debugging actually matters
Your team already knows Redux
You hate yourself
I removed Redux from two projects this year. Replaced with Zustand. Code deleted: ~2000 lines. Bugs fixed: 12.
The State Management Lies
"You need Redux for large apps" - False. Shopify uses Zustand. Netflix uses Zustand.
"Redux DevTools are essential" - I haven't opened them in 2 years. console.log works fine.
"Normalized state is critical" - For 99% of apps, just fetch fresh data. Your users have gigabit internet.
Server State: There's Only One Choice
TanStack Query. Period.
Stop evaluating options. Use TanStack Query (formerly React Query).
// This replaces 500 lines of useEffect garbagefunctionProducts(){const{ data, error, isLoading }=useQuery({queryKey:['products'],queryFn: fetchProducts,staleTime:5*60*1000,// 5 minutes})if(isLoading)return<Skeleton/>if(error)return<Error/>return<ProductList products={data}/>}
Literally. Check the GitHub. Last real update: 2021. Still using Formik? You're maintaining abandonware.
React Hook Form: The Only Option
// This is the entire form logicconst{ register, handleSubmit,formState:{ errors }}=useForm()constonSubmit=async(data)=>{awaitsaveUser(data)}return(<form onSubmit={handleSubmit(onSubmit)}><input {...register('email',{required:true})}/>{errors.email&&<span>Email required</span>}<button type="submit">Save</button></form>)
No providers. No wrapper components. No 10KB of validation schemas.
Validation: Zod + RHF
Stop writing validation twice. Use Zod schemas for both frontend and backend: