React Js

React JS Tutorial Learn React JS, the powerful JavaScript library for building dynamic and interactive user interfaces. This beginner-friendly tutorial covers core concepts like components, state, props, and hooks, with hands-on projects to create responsive web apps. Perfect for aspiring developers looking to master modern front-end development.

React Router : Basics to Advanced Ultimate guide

24 April 2025 | Category:

Welcome to this beginner-friendly tutorial on React Router! React Router is a powerful library for adding client-side routing to React applications, enabling navigation between different views without full page reloads. In this guide, you’ll learn how to set up React Router, define routes, navigate between pages, handle dynamic routes, and protect routes. We’ll apply these concepts by building a Blog App with a homepage, blog post list, individual post pages, and a protected dashboard for adding posts. By the end, you’ll be confident using React Router to create seamless, multi-page experiences in your React applications.


What is React Router?

React Router is a library that enables navigation and rendering of components based on the URL in a React single-page application (SPA). It allows you to map URLs to components, creating the illusion of multiple pages while keeping the app fast and responsive. React Router handles routing on the client side, avoiding server requests for page changes.

Why Learn React Router?

  • Multi-Page Experience: Create apps with distinct views (e.g., home, about, profile) without reloading.
  • Dynamic Routing: Render content based on URL parameters (e.g., /posts/:id for specific posts).
  • Navigation: Enable seamless transitions between views with links or programmatic redirects.
  • Core Skill: Routing is essential for building complex React applications, from dashboards to e-commerce sites.

Prerequisites

Before starting, you should have:

  • Basic knowledge of React (components, props, state, JSX, events, conditional rendering, lists, forms) and JavaScript (ES6).
  • Node.js and npm installed (download from nodejs.org).
  • A code editor like Visual Studio Code.
  • A terminal for running commands.

We’ll use Create React App to set up our project, React Router v6 (the latest version as of April 2025), and Tailwind CSS for responsive, attractive styling, consistent with your preference for visually appealing designs.


Key React Router Concepts

Let’s explore the core concepts for using React Router.

1. Setting Up React Router

Install react-router-dom and wrap your app in a BrowserRouter to enable routing.

Example:

import { BrowserRouter, Routes, Route } from 'react-router-dom';

const App = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </BrowserRouter>
  );
};

2. Defining Routes

Use Routes and Route components to map URLs to components. The path prop defines the URL pattern, and element specifies the component to render.

Example:

<Route path="/contact" element={<Contact />} />

3. Navigation

Use Link for declarative navigation (like <a> tags) and useNavigate for programmatic navigation.

Example:

import { Link, useNavigate } from 'react-router-dom';

const Nav = () => {
  const navigate = useNavigate();
  return (
    <div>
      <Link to="/">Home</Link>
      <button onClick={() => navigate('/about')}>Go to About</button>
    </div>
  );
};

4. Dynamic Routes

Use URL parameters (e.g., :id) to render components dynamically based on the URL.

Example:

<Route path="/post/:id" element={<Post />} />

const Post = () => {
  const { id } = useParams();
  return <h2>Post ID: {id}</h2>;
};

5. Protected Routes

Create custom route components to restrict access based on conditions (e.g., authentication).

Example:

const ProtectedRoute = ({ children }) => {
  const isAuthenticated = false; // Replace with auth logic
  return isAuthenticated ? children : <Navigate to="/login" />;
};

6. Nested Routes

Define routes within routes to create hierarchical layouts, like a dashboard with sub-pages.

Example:

<Route path="/dashboard" element={<Dashboard />}>
  <Route path="profile" element={<Profile />} />
</Route>

Setting Up the Project

Let’s create a React app to build our Blog App, which will use React Router for navigation and routing.

  1. Create a New React App:
    Open your terminal and run: npx create-react-app blog-app cd blog-app
  2. Install Dependencies:
    Install react-router-dom and Tailwind CSS: npm install react-router-dom npm install -D tailwindcss npx tailwindcss init
  3. Configure Tailwind CSS:
    Update tailwind.config.js: /** @type {import('tailwindcss').Config} */ module.exports = { content: ['./src/**/*.{js,jsx,ts,tsx}'], theme: { extend: {} }, plugins: [] }; Update src/index.css: @tailwind base; @tailwind components; @tailwind utilities; body { font-family: Arial, sans-serif; margin: 0; background-color: #f5f5f5; }
  4. Start the Development Server: npm start This opens your app at http://localhost:3000.
  5. Clean Up:
    Open src/App.js and replace its content with: const App = () => { return ( <div className="container mx-auto p-4"> <h1 className="text-3xl font-bold text-gray-800">Blog App</h1> </div> ); }; export default App; Delete src/App.css and src/logo.svg.

Building the Blog App

Our Blog App will:

  • Have a homepage (/), a blog post list (/posts), individual post pages (/posts/:id), and a protected dashboard (/dashboard) for adding posts.
  • Use a navigation bar for routing between pages.
  • Implement dynamic routes for viewing specific posts.
  • Protect the dashboard route to simulate authentication.
  • Use Tailwind CSS for a responsive, visually appealing design, aligning with your preference for attractive UI.

Step 1: Create the Navigation Component

  1. In src, create a file named Nav.js:import { Link, NavLink } from 'react-router-dom'; const Nav = () => { return ( <nav className="bg-blue-500 p-4 mb-6"> <ul className="flex space-x-4 text-white"> <li> <NavLink to="/" className={({ isActive }) => isActive ? 'font-bold underline' : 'hover:underline' } > Home </NavLink> </li> <li> <NavLink to="/posts" className={({ isActive }) => isActive ? 'font-bold underline' : 'hover:underline' } > Posts </NavLink> </li> <li> <NavLink to="/dashboard" className={({ isActive }) => isActive ? 'font-bold underline' : 'hover:underline' } > Dashboard </NavLink> </li> </ul> </nav> ); }; export default Nav;
    • Router Features:
      • Uses NavLink for navigation with active state styling (isActive).
      • Styled with Tailwind CSS for a responsive, blue navigation bar.

Step 2: Create the Home Component

  1. In src, create a file named Home.js:const Home = () => { return ( <div className="max-w-2xl"> <h2 className="text-2xl font-semibold text-gray-800 mb-4"> Welcome to Our Blog </h2> <p className="text-gray-600"> Explore our collection of blog posts or add your own in the dashboard. </p> </div> ); }; export default Home;
    • Router Features:
      • Simple static page for the root route (/).
      • Styled with Tailwind CSS for a clean, centered layout.

Step 3: Create the Posts Component

  1. In src, create a file named Posts.js:import { Link } from 'react-router-dom'; const Posts = ({ posts }) => { return ( <div className="max-w-2xl"> <h2 className="text-2xl font-semibold text-gray-800 mb-4">Blog Posts</h2> {posts.length > 0 ? ( <ul className="space-y-4"> {posts.map((post) => ( <li key={post.id} className="bg-white p-4 rounded-lg shadow-md" > <Link to={`/posts/${post.id}`} className="text-blue-500 hover:underline" > <h3 className="text-lg font-semibold">{post.title}</h3> </Link> <p className="text-gray-600">{post.excerpt}</p> </li> ))} </ul> ) : ( <p className="text-gray-500">No posts available.</p> )} </div> ); }; export default Posts;
    • Router Features:
      • Renders a list of posts with Link components for navigation to dynamic routes (/posts/:id).
      • Uses conditional rendering for empty states.
      • Styled with Tailwind CSS for a responsive, card-based layout.

Step 4: Create the Post Component

  1. In src, create a file named Post.js:import { useParams, useNavigate } from 'react-router-dom'; const Post = ({ posts }) => { const { id } = useParams(); const navigate = useNavigate(); const post = posts.find((p) => p.id === id); if (!post) { return ( <div className="max-w-2xl"> <p className="text-red-500">Post not found.</p> <button onClick={() => navigate('/posts')} className="text-blue-500 hover:underline" > Back to Posts </button> </div> ); } return ( <div className="max-w-2xl"> <h2 className="text-2xl font-semibold text-gray-800 mb-4"> {post.title} </h2> <p className="text-gray-600 mb-4">{post.content}</p> <button onClick={() => navigate('/posts')} className="text-blue-500 hover:underline" > Back to Posts </button> </div> ); }; export default Post;
    • Router Features:
      • Uses useParams to access the dynamic :id from the URL.
      • Uses useNavigate for programmatic navigation back to the posts list.
      • Handles missing posts with a fallback UI.
      • Styled with Tailwind CSS for a clean, readable layout.

Step 5: Create the Dashboard Component

  1. In src, create a file named Dashboard.js:const Dashboard = ({ onAddPost }) => { const [title, setTitle] = React.useState(''); const [content, setContent] = React.useState(''); const handleSubmit = (e) => { e.preventDefault(); if (title.trim() && content.trim()) { onAddPost({ id: Date.now().toString(), title, excerpt: content.slice(0, 100) + '...', content }); setTitle(''); setContent(''); } }; return ( <div className="max-w-2xl"> <h2 className="text-2xl font-semibold text-gray-800 mb-4"> Add New Post </h2> <form onSubmit={handleSubmit} className="space-y-4"> <div> <label className="block text-gray-700 mb-1">Title</label> <input type="text" value={title} onChange={(e) => setTitle(e.target.value)} className="w-full p-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Post title" /> </div> <div> <label className="block text-gray-700 mb-1">Content</label> <textarea value={content} onChange={(e) => setContent(e.target.value)} className="w-full p-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Post content" rows="5" /> </div> <button type="submit" className="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600" > Add Post </button> </form> </div> ); }; export default Dashboard;
    • Router Features:
      • A form for adding new posts, accessible only via the protected /dashboard route.
      • Passes new post data to the parent via onAddPost.
      • Styled with Tailwind CSS for a responsive, form-based layout.

Step 6: Create the ProtectedRoute Component

  1. In src, create a file named ProtectedRoute.js:import { Navigate } from 'react-router-dom'; const ProtectedRoute = ({ children }) => { const isAuthenticated = false; // Replace with real auth logic (e.g., token check) return isAuthenticated ? ( children ) : ( <div className="max-w-2xl"> <p className="text-red-500 mb-4"> You must be logged in to access the dashboard. </p> <NavLink to="/posts" className="text-blue-500 hover:underline"> Back to Posts </NavLink> </div> ); }; export default ProtectedRoute;
    • Router Features:
      • Protects the dashboard route, redirecting unauthenticated users with a message.
      • Uses Navigate for redirection (simplified here with a message for demo purposes).
      • Styled with Tailwind CSS for consistency.

Step 7: Update the App Component

  1. Update src/App.js to define routes and manage posts:import { BrowserRouter, Routes, Route } from 'react-router-dom'; import Nav from './Nav'; import Home from './Home'; import Posts from './Posts'; import Post from './Post'; import Dashboard from './Dashboard'; import ProtectedRoute from './ProtectedRoute'; const App = () => { const [posts, setPosts] = React.useState([ { id: '1', title: 'First Blog Post', excerpt: 'This is the first post on our blog...', content: 'This is the first post on our blog. Welcome to our community!' }, { id: '2', title: 'React Router Basics', excerpt: 'Learn how to use React Router...', content: 'Learn how to use React Router to add navigation to your apps.' } ]); const addPost = (newPost) => { setPosts([...posts, newPost]); }; return ( <BrowserRouter> <div className="container mx-auto p-4"> <Nav /> <Routes> <Route path="/" element={<Home />} /> <Route path="/posts" element={<Posts posts={posts} />} /> <Route path="/posts/:id" element={<Post posts={posts} />} /> <Route path="/dashboard" element={ <ProtectedRoute> <Dashboard onAddPost={addPost} /> </ProtectedRoute> } /> <Route path="*" element={ <div className="max-w-2xl"> <p className="text-red-500">404: Page not found.</p> <NavLink to="/" className="text-blue-500 hover:underline"> Go Home </NavLink> </div> } /> </Routes> </div> </BrowserRouter> ); }; export default App;
    • Router Features:
      • Wraps the app in BrowserRouter and defines routes with Routes and Route.
      • Includes routes for home (/), posts (/posts), dynamic post (/posts/:id), and protected dashboard (/dashboard).
      • Uses a catch-all route (*) for 404 errors.
      • Manages posts in state and passes them to Posts and Post, with addPost for the dashboard.
      • Uses Tailwind CSS for a responsive, centered layout.

Step 8: Test the App

  • Save all files and ensure the development server is running (npm start).
  • Open http://localhost:3000. You should see:
    • A navigation bar with links to Home, Posts, and Dashboard.
    • The homepage at / with a welcome message.
    • A list of posts at /posts with clickable titles linking to /posts/:id.
    • Individual post pages showing content and a back button.
    • A protected dashboard at /dashboard showing an access denied message (since isAuthenticated is false).
    • A 404 page for invalid URLs (e.g., /random).
  • Try:
    • Navigating between pages using the nav bar.
    • Clicking a post title to view its details and using the back button.
    • Accessing /dashboard to see the protected route message.
    • Visiting an invalid URL to test the 404 page.
    • Checking responsiveness by resizing the browser or using mobile view in dev tools.

Understanding the Code

Let’s recap how React Router powers our Blog App:

  • Setup: BrowserRouter enables routing, with Routes and Route mapping URLs to components.
  • Navigation: Nav uses NavLink for styled navigation, and Post uses useNavigate for programmatic redirects.
  • Dynamic Routes: Post uses useParams to access :id and render specific post data.
  • Protected Routes: ProtectedRoute restricts access to Dashboard, showing a fallback UI.
  • Nested Structure: The app uses a flat route structure for simplicity, but Nav is shared across pages.
  • Responsive Design: Tailwind CSS ensures a mobile-friendly layout with a sticky nav and card-based posts, aligning with your preference for attractive, responsive UI.
  • ES6 Features:
    • Arrow functions for components and handlers.
    • Destructuring ({ id }, posts).
    • Spread operator for state updates ([...posts, newPost]).
    • Modules for component organization.

Best Practices for React Router

  • Use NavLink for Active Styles: Apply styles to active routes with NavLink’s isActive:<NavLink className={({ isActive }) => isActive ? 'active' : ''}>Link</NavLink>
  • Handle 404s: Include a catch-all route for invalid URLs:<Route path="*" element={<NotFound />} />
  • Keep Routes Organized: Group related routes in a logical structure, using nested routes for layouts.
  • Use Stable Keys: Ensure list items in routed components have unique, stable key props:posts.map((post) => <li key={post.id}>...</li>)
  • Optimize Protected Routes: Implement real authentication (e.g., with tokens) and redirect gracefully:return isAuthenticated ? children : <Navigate to="/login" />;
  • Test Navigation: Verify all routes and links work across devices, using browser dev tools for mobile testing.

Common React Router Pitfalls and Fixes

  • Missing BrowserRouter:
    Problem: Routes don’t work because BrowserRouter is missing.
    Fix: Wrap the app in BrowserRouter:<BrowserRouter><Routes>...</Routes></BrowserRouter>
  • Incorrect Path Matching:
    Problem: Routes don’t render due to exact path mismatches.
    Fix: Use path correctly and test with / or dynamic params:<Route path="/posts/:id" element={<Post />} />
  • Broken Links:
    Problem: Using <a> tags causes full page reloads.
    Fix: Use Link or NavLink:<Link to="/posts">Posts</Link>
  • Dynamic Route Errors:
    Problem: useParams returns undefined or data is missing.
    Fix: Validate params and handle missing data:const { id } = useParams(); if (!data) return <p>Not found</p>;
  • Unprotected Routes:
    Problem: Sensitive routes are accessible without checks.
    Fix: Use a ProtectedRoute component with auth logic.

React Router in Functional vs. Class Components

Since you’ve explored class components previously, here’s how routing differs:

  • Functional Components: Use hooks (useParams, useNavigate, useLocation) for routing logic:const Post = () => { const { id } = useParams(); return <p>Post: {id}</p>; };
  • Class Components: Use withRouter (in older versions) or wrap with hooks in v6, accessing props like this.props.match.params:class Post extends React.Component { render() { const { id } = this.props.match.params; return <p>Post: {id}</p>; } }

Our app uses functional components with hooks for simplicity and alignment with modern React, but routing concepts apply to both.


What’s Next?

You’ve built a Blog App using React Router! Here are some next steps:

  • Add Features: Implement a login page to toggle isAuthenticated and enable dashboard access.
  • Learn More Techniques: Explore Outlet for nested routes or useLocation for tracking URL changes.
  • Enhance Styling: Add animations with Tailwind CSS or Framer Motion for route transitions.
  • Build Another App: Create a portfolio site or e-commerce app with routing.

Practice Challenge

Add a “Login” page at /login with a form that sets isAuthenticated to true (stored in state). Update ProtectedRoute to redirect to /login for unauthenticated users, preserving the intended URL for post-login redirection.


Resources

Congratulations on mastering React Router! You’re now equipped to build multi-page experiences with seamless navigation. Keep practicing and happy coding!