Error boundaries for graceful error handling

React error boundaries catch JavaScript errors in child components, log them, and display fallback UI instead of crashing the entire app. Since error boundaries must be class components in React, I create a generic ErrorBoundary wrapper and use it aro

Custom hooks for reusable logic

Custom hooks extract component logic into reusable functions that can share stateful behavior across components. I prefix hook names with use and compose them from built-in hooks like useState, useEffect, and useCallback. Hooks encapsulate concerns li

Optimistic updates with React Query mutations

Optimistic updates make UIs feel instant by immediately showing the expected result before the server confirms. When a user likes a post, I update the local cache immediately, submit the request in background, and rollback if it fails. React Query's m

Form handling with React Hook Form

React Hook Form provides performant form handling with minimal re-renders. Unlike controlled components that re-render on every keystroke, it uses uncontrolled inputs with refs. The register function connects inputs to the form state, and handleSubmit

React Router with protected routes

React Router v6 provides declarative routing with data loading and authentication guards. I wrap protected routes in a ProtectedRoute component that checks authentication state from context and redirects to login if needed. The Navigate component hand

Context API for global UI state

While React Query handles server state, I use Context API for client-side UI state like theme, sidebar visibility, or current user. Each context lives in its own file with a custom hook for consuming it. The context provider wraps the app at a high le

TypeScript types from Rails serializers

Keeping TypeScript types in sync with Rails API responses is critical but tedious. I generate TypeScript interfaces automatically from Rails serializers or JSON Schema using tools like quicktype or custom scripts. For manual definitions, I create a ty

React Query for server state management

React Query eliminates boilerplate for fetching, caching, and syncing server data. Instead of managing loading/error/data states manually with useState, I define queries with useQuery that handle caching, background refetching, and stale data automati

Axios API client with interceptors

A centralized API client provides a single place to configure authentication, error handling, and request/response transformations. I use axios for its interceptor support and automatic JSON transformation. Request interceptors attach the JWT token fr

React app structure with Vite and TypeScript

Vite provides lightning-fast dev server startup and hot module replacement compared to Create React App. I scaffold React projects with TypeScript for type safety across the entire frontend. The folder structure separates concerns: components for reus

Rails API-only app setup for React frontend

When building a React SPA, I configure Rails in API-only mode to skip view rendering, asset pipeline, and session cookies. The --api flag generates a lean Rails app focused on JSON responses. I enable CORS to allow the React dev server on localhost:51

Hotwire-powered multi-step forms

Multi-step forms traditionally require complex JavaScript state management, but Hotwire makes them simple. Each step is a separate controller action that renders a Turbo Frame containing the current step's fields. Navigation between steps updates only