react-router and vue-router are the standard routing libraries for React and Vue ecosystems respectively. They manage navigation, URL synchronization, and component rendering based on the current path. react-router has evolved to include data loading and action handling directly within the routing layer (v6.4+), while vue-router focuses on tight integration with Vue's reactivity system and lifecycle hooks. Both handle history management, nested routes, and programmatic navigation, but they differ significantly in how routes are defined and how data is fetched during transitions.
Both react-router and vue-router solve the core problem of client-side navigation: mapping URLs to UI components without reloading the page. However, their implementation details reflect the philosophies of their host frameworks. React Router leans into JSX and component composition, while Vue Router favors configuration objects and reactive integration. Let's examine how they handle real-world routing challenges.
react-router defines routes using JSX components.
<Route> elements inside a <Routes> container.// react-router: Component-based routes
import { Routes, Route } from "react-router-dom";
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
);
}
vue-router defines routes using a JavaScript array of objects.
routes configuration.// vue-router: Configuration-based routes
import { createRouter, createWebHistory } from "vue-router";
const routes = [
{ path: "/", component: Home },
{ path: "/about", component: About }
];
const router = createRouter({
history: createWebHistory(),
routes
});
react-router provides hooks for programmatic navigation.
useNavigate to change paths inside components.// react-router: Hook-based navigation
import { useNavigate } from "react-router-dom";
function LoginButton() {
const navigate = useNavigate();
const handleLogin = () => {
// Redirect after success
navigate("/dashboard");
};
return <button onClick={handleLogin}>Login</button>;
}
vue-router exposes a router instance or composables.
router.push directly or the useRouter composable in setup.// vue-router: Instance-based navigation
import { useRouter } from "vue-router";
export default {
setup() {
const router = useRouter();
const handleLogin = () => {
// Redirect after success
router.push("/dashboard");
};
return { handleLogin };
}
};
react-router uses the <Outlet /> component to render child routes.
<Outlet /> where children should appear.// react-router: Nested routes with Outlet
<Route path="/dashboard" element={<DashboardLayout />}>
<Route index element={<DashboardHome />} />
<Route path="settings" element={<Settings />} />
</Route>
// DashboardLayout.jsx
function DashboardLayout() {
return (
<div>
<Sidebar />
<Outlet /> {/* Child routes render here */}
</div>
);
}
vue-router uses <router-view /> to render matched children.
<router-view /> in the parent component template.<!-- vue-router: Nested routes with router-view -->
<!-- Parent Component Template -->
<template>
<div>
<Sidebar />
<router-view /> <!-- Child routes render here -->
</div>
</template>
<!-- Route Config -->
const routes = [
{
path: "/dashboard",
component: DashboardLayout,
children: [
{ path: "", component: DashboardHome },
{ path: "settings", component: Settings }
]
}
];
react-router (v6.4+) includes built-in data APIs.
loader functions on routes to fetch data before rendering.useLoaderData to access the result inside the component.// react-router: Built-in data loading
const router = createBrowserRouter([
{
path: "/user/:id",
element: <UserProfile />,
loader: async ({ params }) => {
return fetch(`/api/user/${params.id}`);
}
}
]);
// In Component
function UserProfile() {
const user = useLoaderData();
return <div>{user.name}</div>;
}
vue-router relies on navigation guards or setup fetching.
beforeRouteEnter or onBeforeRouteUpdate to trigger fetches.// vue-router: Guard-based or setup fetching
const routes = [
{
path: "/user/:id",
component: UserProfile,
beforeEnter: async (to) => {
// Fetch data before entering
const user = await fetch(`/api/user/${to.params.id}`);
to.meta.user = user;
}
}
];
// In Component (Composition API)
export default {
setup() {
const route = useRoute();
const user = ref(null);
watch(() => route.params.id, async (id) => {
user.value = await fetch(`/api/user/${id}`);
}, { immediate: true });
return { user };
}
};
react-router handles redirects by throwing responses in loaders.
// react-router: Redirect in loader
loader: async ({ request }) => {
const user = await getUser(request);
if (!user) {
throw redirect("/login");
}
return user;
};
vue-router uses global or per-route guards.
beforeEach or beforeEnter.next("/login") to redirect if the check fails.// vue-router: Redirect in guard
router.beforeEach((to, from, next) => {
const isAuthenticated = checkAuth();
if (to.meta.requiresAuth && !isAuthenticated) {
next("/login");
} else {
next();
}
});
While the APIs differ, both libraries solve the same fundamental problems with similar capabilities.
// react-router: History config
createBrowserRouter(routes); // Uses HTML5 history by default
// vue-router: History config
createWebHistory(); // Uses HTML5 history
createWebHashHistory(); // Uses hash routing
// react-router: Link component
import { Link } from "react-router-dom";
<Link to="/about" className="active">About</Link>;
<!-- vue-router: RouterLink component -->
<router-link to="/about" custom v-slot="{ isActive }">
<a :class="{ active: isActive }">About</a>
</router-link>
/user/:id).// react-router: Accessing params
const { id } = useParams();
// vue-router: Accessing params
const { id } = useRoute().params;
// Example: Ecosystem tools
// react-router: react-router-dom, history
// vue-router: vue-router, pinia (often used together for state)
| Feature | Shared by React Router and Vue Router |
|---|---|
| Core Function | π Client-side URL synchronization |
| History API | π°οΈ HTML5 History & Hash support |
| Navigation | π Declarative Link components |
| Params | π― Dynamic route parameters |
| Ecosystem | π‘οΈ Standard choice for React/Vue |
| Feature | react-router | vue-router |
|---|---|---|
| Route Definition | π§© JSX Components (<Route>) | π Config Array (routes: []) |
| Nested Rendering | πͺ <Outlet /> Component | πͺ <router-view /> Component |
| Navigation API | πͺ useNavigate Hook | ποΈ router.push Instance |
| Data Loading | π¦ Built-in loader API (v6.4+) | π οΈ Guards or Manual Setup Fetching |
| Auth Redirects | π« Throw redirect() in loader | π« Call next("/login") in guard |
react-router is like a set of building blocks π§± β you construct your routing structure using components that fit into your JSX tree. It is ideal for React teams who want routing logic to feel like just another part of the component hierarchy. The newer data APIs make it a strong contender for full-stack style data fetching within the frontend.
vue-router is like a central dispatch system π β you define your map in one place and the router manages the flow. It is perfect for Vue teams who prefer separating configuration from UI logic. Its integration with Vue's reactivity makes handling route changes in components very smooth.
Final Thought: Both libraries are mature and stable. The choice is usually dictated by your framework choice (React vs Vue). If you are starting a new project, pick the router that matches your UI library to ensure the best developer experience and community support.
Choose react-router if you are building a React application and need a routing solution that integrates deeply with React components. It is the standard choice for the React ecosystem, offering a component-based API for defining routes. The newer versions include built-in data loading features that reduce the need for external state management libraries for server interactions.
Choose vue-router if you are working within the Vue.js ecosystem. It is officially maintained and designed to work seamlessly with Vue's reactivity system and composition API. It provides a declarative configuration style for routes and robust navigation guards that fit naturally into Vue application logic.
react-router is the primary package in the React Router project.
npm i react-router