import { Navigate, useLocation } from 'react-router-dom'
import { useAuth } from '@/contexts/AuthContext'
interface ProtectedRouteProps {
children: React.ReactNode
}
export function ProtectedRoute({ children }: ProtectedRouteProps) {
const { isAuthenticated, loading } = useAuth()
const location = useLocation()
if (loading) {
return <div>Loading...</div>
}
if (!isAuthenticated) {
return <Navigate to="/login" state={{ from: location }} replace />
}
return <>{children}</>
}
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
import { Suspense, lazy } from 'react'
import { AuthProvider } from '@/contexts/AuthContext'
import { ProtectedRoute } from '@/components/ProtectedRoute'
import Layout from '@/components/Layout'
const Home = lazy(() => import('@/pages/Home'))
const Login = lazy(() => import('@/pages/Login'))
const Posts = lazy(() => import('@/pages/Posts'))
const PostDetail = lazy(() => import('@/pages/PostDetail'))
const NewPost = lazy(() => import('@/pages/NewPost'))
function App() {
return (
<AuthProvider>
<BrowserRouter>
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/login" element={<Login />} />
<Route element={<Layout />}>
<Route path="/" element={<Home />} />
<Route path="/posts" element={<Posts />} />
<Route path="/posts/:id" element={<PostDetail />} />
<Route
path="/posts/new"
element={
<ProtectedRoute>
<NewPost />
</ProtectedRoute>
}
/>
</Route>
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</Suspense>
</BrowserRouter>
</AuthProvider>
)
}
export default App
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 handles redirects while preserving the attempted URL so users land where they intended after logging in. Nested routes share layouts via Outlet, avoiding component duplication. The useNavigate hook enables programmatic navigation after form submissions. Lazy loading route components with React.lazy and Suspense keeps initial bundle sizes small. This routing setup handles complex multi-page apps while maintaining type safety with TypeScript.