Appearance
React Router (Vue Router in a trench coat)
Routes, nested layouts, params - same problems. Different file of configuration.
We'll use React Router v6/v7 style APIs (the createBrowserRouter world). Install:
bash
npm install react-router(Package name has been consolidating - follow the current React Router docs for your major version. The concepts below stay stable.)
Basic setup
tsx
// main.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { createBrowserRouter, RouterProvider } from 'react-router'
import App from './App'
import Home from './pages/Home'
import About from './pages/About'
const router = createBrowserRouter([
{
path: '/',
element: <App />,
children: [
{ index: true, element: <Home /> },
{ path: 'about', element: <About /> },
],
},
])
createRoot(document.getElementById('root')!).render(
<StrictMode>
<RouterProvider router={router} />
</StrictMode>,
)Comments for the code above:
- Nested
children≈ Vue Router nested routes + layout index: true≈ empty child path / default childAppshould render an<Outlet />where children appear
Layout with Outlet
tsx
import { Outlet, Link } from 'react-router'
export default function App() {
return (
<div>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Outlet />
</div>
)
}As you can see - <Outlet /> is <RouterView />. <Link> is <RouterLink>.
Params
tsx
// route: { path: 'users/:id', element: <UserPage /> }
import { useParams } from 'react-router'
function UserPage() {
const { id } = useParams()
return <p>User {id}</p>
}Same energy as route.params.id / useRoute().params.
Navigate programmatically
tsx
import { useNavigate } from 'react-router'
const navigate = useNavigate()
navigate('/about')
navigate(-1) // back≈ router.push / router.back.
Vue Router → React Router cheat
| Vue Router | React Router |
|---|---|
RouterView | Outlet |
RouterLink | Link |
useRoute() | useParams, useLocation, useMatch |
useRouter().push | useNavigate() |
| navigation guards | loaders / actions / your own wrappers (or auth layout routes) |
Auth-ish layout (simple pattern)
tsx
{
path: '/app',
element: <RequireAuth><AppLayout /></RequireAuth>,
children: [
{ path: 'dashboard', element: <Dashboard /> },
],
}RequireAuth checks a token/context and either renders children or <Navigate to="/login" replace />. Not as fancy as global beforeEach, but clear.
We'll touch loaders lightly later if you go Next instead - for Vite SPAs, fetch in components or TanStack Query is the usual path I've seen.
Next: fetching without a library - then why you'll want one.
Enjoy!