# Routing Guide TanStack Router implementation with folder-based routing and lazy loading patterns. --- ## TanStack Router Overview **TanStack Router** with file-based routing: - Folder structure defines routes - Lazy loading for code splitting - Type-safe routing - Breadcrumb loaders --- ## Folder-Based Routing ### Directory Structure ``` routes/ __root.tsx # Root layout index.tsx # Home route (/) posts/ index.tsx # /posts create/ index.tsx # /posts/create $postId.tsx # /posts/:postId (dynamic) comments/ index.tsx # /comments ``` **Pattern**: - `index.tsx` = Route at that path - `$param.tsx` = Dynamic parameter - Nested folders = Nested routes --- ## Basic Route Pattern ### Example from posts/index.tsx ```typescript /** * Posts route component * Displays the main blog posts list */ import { createFileRoute } from '@tanstack/react-router'; import { lazy } from 'react'; // Lazy load the page component const PostsList = lazy(() => import('@/features/posts/components/PostsList').then( (module) => ({ default: module.PostsList }), ), ); export const Route = createFileRoute('/posts/')({ component: PostsPage, // Define breadcrumb data loader: () => ({ crumb: 'Posts', }), }); function PostsPage() { return ( ); } export default PostsPage; ``` **Key Points:** - Lazy load heavy components - `createFileRoute` with route path - `loader` for breadcrumb data - Page component renders content - Export both Route and component --- ## Lazy Loading Routes ### Named Export Pattern ```typescript import { lazy } from 'react'; // For named exports, use .then() to map to default const MyPage = lazy(() => import('@/features/my-feature/components/MyPage').then( (module) => ({ default: module.MyPage }) ) ); ``` ### Default Export Pattern ```typescript import { lazy } from 'react'; // For default exports, simpler syntax const MyPage = lazy(() => import('@/features/my-feature/components/MyPage')); ``` ### Why Lazy Load Routes? - Code splitting - smaller initial bundle - Faster initial page load - Load route code only when navigated to - Better performance --- ## createFileRoute ### Basic Configuration ```typescript export const Route = createFileRoute('/my-route/')({ component: MyRoutePage, }); function MyRoutePage() { return
My Route Content
; } ``` ### With Breadcrumb Loader ```typescript export const Route = createFileRoute('/my-route/')({ component: MyRoutePage, loader: () => ({ crumb: 'My Route Title', }), }); ``` Breadcrumb appears in navigation/app bar automatically. ### With Data Loader ```typescript export const Route = createFileRoute('/my-route/')({ component: MyRoutePage, loader: async () => { // Can prefetch data here const data = await api.getData(); return { crumb: 'My Route', data }; }, }); ``` ### With Search Params ```typescript export const Route = createFileRoute('/search/')({ component: SearchPage, validateSearch: (search: Record) => { return { query: (search.query as string) || '', page: Number(search.page) || 1, }; }, }); function SearchPage() { const { query, page } = Route.useSearch(); // Use query and page } ``` --- ## Dynamic Routes ### Parameter Routes ```typescript // routes/users/$userId.tsx export const Route = createFileRoute('/users/$userId')({ component: UserPage, }); function UserPage() { const { userId } = Route.useParams(); return ; } ``` ### Multiple Parameters ```typescript // routes/posts/$postId/comments/$commentId.tsx export const Route = createFileRoute('/posts/$postId/comments/$commentId')({ component: CommentPage, }); function CommentPage() { const { postId, commentId } = Route.useParams(); return ; } ``` --- ## Navigation ### Programmatic Navigation ```typescript import { useNavigate } from '@tanstack/react-router'; export const MyComponent: React.FC = () => { const navigate = useNavigate(); const handleClick = () => { navigate({ to: '/posts' }); }; return ; }; ``` ### With Parameters ```typescript const handleNavigate = () => { navigate({ to: '/users/$userId', params: { userId: '123' }, }); }; ``` ### With Search Params ```typescript const handleSearch = () => { navigate({ to: '/search', search: { query: 'test', page: 1 }, }); }; ``` --- ## Route Layout Pattern ### Root Layout (__root.tsx) ```typescript import { createRootRoute, Outlet } from '@tanstack/react-router'; import { Box } from '@mui/material'; import { CustomAppBar } from '~components/CustomAppBar'; export const Route = createRootRoute({ component: RootLayout, }); function RootLayout() { return ( {/* Child routes render here */} ); } ``` ### Nested Layouts ```typescript // routes/dashboard/index.tsx export const Route = createFileRoute('/dashboard/')({ component: DashboardLayout, }); function DashboardLayout() { return ( {/* Nested routes */} ); } ``` --- ## Complete Route Example ```typescript /** * User profile route * Path: /users/:userId */ import { createFileRoute } from '@tanstack/react-router'; import { lazy } from 'react'; import { SuspenseLoader } from '~components/SuspenseLoader'; // Lazy load heavy component const UserProfile = lazy(() => import('@/features/users/components/UserProfile').then( (module) => ({ default: module.UserProfile }) ) ); export const Route = createFileRoute('/users/$userId')({ component: UserPage, loader: () => ({ crumb: 'User Profile', }), }); function UserPage() { const { userId } = Route.useParams(); return ( ); } export default UserPage; ``` --- ## Summary **Routing Checklist:** - ✅ Folder-based: `routes/my-route/index.tsx` - ✅ Lazy load components: `React.lazy(() => import())` - ✅ Use `createFileRoute` with route path - ✅ Add breadcrumb in `loader` function - ✅ Wrap in `SuspenseLoader` for loading states - ✅ Use `Route.useParams()` for dynamic params - ✅ Use `useNavigate()` for programmatic navigation **See Also:** - [component-patterns.md](component-patterns.md) - Lazy loading patterns - [loading-and-error-states.md](loading-and-error-states.md) - SuspenseLoader usage - [complete-examples.md](complete-examples.md) - Full route examples