Epic Stack: React Patterns and Guidelines
When to use this skill
Use this skill when you need to:
Write efficient React components in Epic Stack applications
Optimize performance and bundle size
Follow React Router patterns and conventions
Avoid common React anti-patterns
Implement proper code splitting
Optimize re-renders and data fetching
Use React hooks correctly
Philosophy
Following Epic Web principles:
Make it work, make it right, make it fast - In that order. First make it functional, then refactor for clarity, then optimize for performance.
Pragmatism over purity - Choose practical solutions that work well in your context rather than theoretically perfect ones.
Optimize for sustainable velocity - Write code that's easy to maintain and extend, not just fast to write initially.
Do as little as possible - Only add complexity when it provides real value.
Patterns and conventions
Data Fetching in React Router
Epic Stack uses React Router loaders for data fetching, not useEffect.
✅ Good - Use loaders:
// app/routes/users/$username.tsx
export async function loader({ params }: Route.LoaderArgs) {
const user = await prisma.user.findUnique({
where: { username: params.username },
})
return { user }
}
export default function UserRoute({ loaderData }: Route.ComponentProps) {
return
{loaderData.user.name}
}
❌ Avoid - Don't fetch in useEffect:
// ❌ Don't do this
export default function UserRoute({ params }: Route.ComponentProps) {
const [user, setUser] = useState(null)
// ❌ Don't do this
function ProductPage({ product, addToCart }: Route.ComponentProps) {
useEffect(() => {
if (product.isInCart) {
showNotification(Added ${product.name} to cart!)
}
}, [product])
function handleBuyClick() {
addToCart(product)
}
// ...
}
✅ Appropriate use of useEffect:
// ✅ Good - Event listeners are appropriate
useEffect(() => {
const controller = new AbortController()
// ❌ Don't memoize simple values
const count = useMemo(() => items.length, [items]) // Just use items.length directly
// ❌ Don't memoize simple callbacks
const handleClick = useCallback(() => {
console.log('clicked')
}, []) // Just define the function normally if it doesn't need memoization
Bundle Size Optimization
✅ Good - Import only what you need:
// ✅ Import specific functions
import { useSearchParams } from 'react-router'
import { parseWithZod } from '@conform-to/zod'
❌ Avoid - Barrel imports:
// ❌ Don't import entire libraries if you only need one thing
import * as ReactRouter from 'react-router'
import * as Conform from '@conform-to/zod'
Form Handling with Conform
✅ Good - Use Conform for forms:
import { useForm, getFormProps } from '@conform-to/react'
import { parseWithZod } from '@conform-to/zod'
import { Form } from 'react-router'
✅ Good - Route-based code splitting: React Router automatically splits code by route. Leverage this:
// Heavy dependencies are automatically split by route
// app/routes/admin/dashboard.tsx
import { Chart } from 'chart.js' // Only loaded on /admin/dashboard route
Common mistakes to avoid
❌ Fetching data in useEffect: Use React Router loaders instead
❌ Overusing useEffect: Prefer event handlers, CSS, or ref callbacks
❌ Premature memoization: Only memoize when there's a measurable performance benefit
❌ Barrel imports: Import only what you need
❌ Ignoring TypeScript types: Use Route types for type safety
❌ Not handling loading states: Use React Router's navigation states
❌ Large monolithic components: Break components into smaller, focused pieces
❌ Not using error boundaries: Always add error boundaries to routes
❌ Client-side routing when server-side works: Prefer server-side data fetching
❌ Data fetching waterfalls: Use Promise.all() to fetch data in parallel
❌ Fetching unnecessary data: Only fetch what's needed for the initial render
❌ Creating new objects in render: Compute derived data in loaders or memoize
❌ Not using React.memo for expensive lists: Memoize list items for better performance
❌ Not leveraging route-based code splitting: React Router splits by route automatically
References
React Router Documentation
React Documentation - You Might Not Need useEffect
Conform Documentation
Epic Stack Docs
Epic Web Principles
app/routes/ - Example routes using these patterns
.cursor/rules/avoid-use-effect.mdc - Epic Stack rule for avoiding useEffect