dev.log / syntax diaries

Practical code notes, tools, and guided learning for developers.

Practical guides, developer tools, and tutorials for modern web developers, with the same focused tone across writing, utilities, and learning tracks.

BlogToolsTutorialsAboutContactAdmin Login
Privacy PolicyTerms of ServiceCookie Policy

ยฉ 2026 The Syntax Diaries ยท System_Operational

The Syntax Diaries logoThe Syntax Diaries
BlogToolsTutorialsAbout
build log live
Tutorial / React
Routing50 minbeginner

React Router

Learn how to add navigation and multiple pages to your React applications using React Router for seamless single-page app experiences.

On This Page

The Problem: Single Page LimitationsWhat is React Router?Setting Up React RouterYour First React Router AppURL Parameters and Dynamic RoutesNested Routes and LayoutsProgrammatic NavigationQuery Parameters and Search404 Pages and Error HandlingPractice Exercise: Build a Product CatalogRouter Best Practices1. Organize Routes Logically2. Use Loading States3. Handle Navigation States4. Use Breadcrumbs for Deep NavigationWhat We've LearnedQuick Recap QuizWhat's Next?

React Router#

Imagine you're building a house. You could make it one giant room, but that would be impractical! Instead, you create different rooms - kitchen, bedroom, living room - and hallways to move between them. React Router does the same thing for your React apps, allowing you to create different "pages" and navigate between them seamlessly.

Without React Router, your entire app would be stuck on a single page. With it, you can build full-featured Single Page Applications (SPAs) that feel just like traditional multi-page websites, but with the speed and interactivity of React.

The Problem: Single Page Limitations#

By default, React apps live on a single page. Everything happens in one URL:

// Without routing - everything in one component!
function App() {
  const [currentPage, setCurrentPage] = useState('home');
  
  return (
    <div>
      <nav>
        <button onClick={() => setCurrentPage('home')}>Home</button>
        <button onClick={() => setCurrentPage('about')}>About</button>
        <button onClick={() => setCurrentPage('contact')}>Contact</button>
      </nav>
      
      {currentPage === 'home' && <HomePage />}
      {currentPage === 'about' && <AboutPage />}
      {currentPage === 'contact' && <ContactPage />}
    </div>
  );
}

Problems with this approach:

  • ๐Ÿšซ URL doesn't change - users can't bookmark specific pages
  • ๐Ÿšซ No browser back/forward - breaks user expectations
  • ๐Ÿšซ Hard to share links - everything is just "mysite.com"
  • ๐Ÿšซ No deep linking - can't send someone directly to a specific page
  • ๐Ÿšซ SEO issues - search engines can't index different pages

What is React Router?#

React Router is the standard library for adding routing to React applications. It enables:

โœ… Different URLs for different content (/home, /about, /contact)
โœ… Browser navigation (back/forward buttons work)
โœ… Bookmarkable pages (users can save and return to specific pages)
โœ… Deep linking (share links to specific content)
โœ… Nested routing (complex page structures)

Think of it as the "GPS system" for your React app!

Setting Up React Router#

First, you need to install React Router DOM:

npm install react-router-dom

Then wrap your app with a router:

import React from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import HomePage from './components/HomePage';
import AboutPage from './components/AboutPage';
import ContactPage from './components/ContactPage';

function App() {
  return (
    <BrowserRouter>
      <div>
        <nav>
          {/* We'll add navigation links here */}
        </nav>
        
        <Routes>
          <Route path="/" element={<HomePage />} />
          <Route path="/about" element={<AboutPage />} />
          <Route path="/contact" element={<ContactPage />} />
        </Routes>
      </div>
    </BrowserRouter>
  );
}

export default App;

Key components:

  • BrowserRouter: Provides routing context to your entire app
  • Routes: Container for all your route definitions
  • Route: Defines a path and what component to show

Your First React Router App#

Let's build a simple blog-style website to understand the basics:

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

// Page Components
function HomePage() {
  return (
    <div style={{ padding: '20px' }}>
      <h1>๐Ÿ  Welcome to My Blog</h1>
      <p>This is the home page where we showcase featured articles.</p>
      
      <div style={{ 
        display: 'grid', 
        gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
        gap: '20px',
        marginTop: '30px'
      }}>
        <div style={{ 
          border: '1px solid #ddd', 
          padding: '15px', 
          borderRadius: '8px' 
        }}>
          <h3>Getting Started with React</h3>
          <p>Learn the basics of React development...</p>
          <Link to="/blog/react-basics" style={{ color: '#0066cc' }}>
            Read more โ†’
          </Link>
        </div>
        
        <div style={{ 
          border: '1px solid #ddd', 
          padding: '15px', 
          borderRadius: '8px' 
        }}>
          <h3>Understanding JavaScript</h3>
          <p>Master JavaScript fundamentals...</p>
          <Link to="/blog/javascript-guide" style={{ color: '#0066cc' }}>
            Read more โ†’
          </Link>
        </div>
      </div>
    </div>
  );
}

function AboutPage() {
  return (
    <div style={{ padding: '20px' }}>
      <h1>๐Ÿ“– About This Blog</h1>
      <p>Welcome to my corner of the internet!</p>
      
      <div style={{ 
        backgroundColor: '#f8f9fa', 
        padding: '20px', 
        borderRadius: '8px',
        marginTop: '20px'
      }}>
        <h2>My Story</h2>
        <p>
          I'm a passionate developer who loves sharing knowledge about 
          web development, particularly React and modern JavaScript.
        </p>
        
        <h3>What You'll Find Here</h3>
        <ul>
          <li>๐Ÿš€ React tutorials and tips</li>
          <li>๐Ÿ’ป JavaScript best practices</li>
          <li>๐ŸŽจ CSS and design insights</li>
          <li>๐Ÿ› ๏ธ Development tools and workflows</li>
        </ul>
      </div>
    </div>
  );
}

function BlogPage() {
  const posts = [
    { id: 'react-basics', title: 'Getting Started with React', date: '2024-01-15' },
    { id: 'javascript-guide', title: 'Understanding JavaScript', date: '2024-01-10' },
    { id: 'css-tips', title: 'CSS Tips and Tricks', date: '2024-01-05' }
  ];
  
  return (
    <div style={{ padding: '20px' }}>
      <h1>๐Ÿ“ Blog Posts</h1>
      <p>All my articles about web development.</p>
      
      <div style={{ marginTop: '30px' }}>
        {posts.map(post => (
          <article key={post.id} style={{
            border: '1px solid #eee',
            padding: '20px',
            marginBottom: '20px',
            borderRadius: '8px'
          }}>
            <h2>
              <Link 
                to={'/blog/' + post.id}
                style={{ color: '#333', textDecoration: 'none' }}
              >
                {post.title}
              </Link>
            </h2>
            <p style={{ color: '#666', fontSize: '14px' }}>
              Published on {new Date(post.date).toLocaleDateString()}
            </p>
            <p>
              Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
              Click to read the full article...
            </p>
            <Link to={'/blog/' + post.id} style={{ color: '#0066cc' }}>
              Read full article โ†’
            </Link>
          </article>
        ))}
      </div>
    </div>
  );
}

function ContactPage() {
  const [formData, setFormData] = React.useState({
    name: '',
    email: '',
    message: ''
  });
  
  const handleSubmit = (e) => {
    e.preventDefault();
    alert('Message sent! (This is just a demo)');
    setFormData({ name: '', email: '', message: '' });
  };
  
  const handleChange = (e) => {
    setFormData({
      ...formData,
      [e.target.name]: e.target.value
    });
  };
  
  return (
    <div style={{ padding: '20px', maxWidth: '600px' }}>
      <h1>๐Ÿ“ง Get In Touch</h1>
      <p>Have a question or want to collaborate? I'd love to hear from you!</p>
      
      <form onSubmit={handleSubmit} style={{ marginTop: '30px' }}>
        <div style={{ marginBottom: '20px' }}>
          <label style={{ display: 'block', marginBottom: '5px' }}>
            Name
          </label>
          <input
            type="text"
            name="name"
            value={formData.name}
            onChange={handleChange}
            required
            style={{
              width: '100%',
              padding: '10px',
              border: '1px solid #ddd',
              borderRadius: '4px'
            }}
          />
        </div>
        
        <div style={{ marginBottom: '20px' }}>
          <label style={{ display: 'block', marginBottom: '5px' }}>
            Email
          </label>
          <input
            type="email"
            name="email"
            value={formData.email}
            onChange={handleChange}
            required
            style={{
              width: '100%',
              padding: '10px',
              border: '1px solid #ddd',
              borderRadius: '4px'
            }}
          />
        </div>
        
        <div style={{ marginBottom: '20px' }}>
          <label style={{ display: 'block', marginBottom: '5px' }}>
            Message
          </label>
          <textarea
            name="message"
            value={formData.message}
            onChange={handleChange}
            required
            rows={5}
            style={{
              width: '100%',
              padding: '10px',
              border: '1px solid #ddd',
              borderRadius: '4px',
              resize: 'vertical'
            }}
          />
        </div>
        
        <button
          type="submit"
          style={{
            backgroundColor: '#0066cc',
            color: 'white',
            padding: '12px 24px',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Send Message
        </button>
      </form>
    </div>
  );
}

// Navigation Component
function Navigation() {
  return (
    <nav style={{
      backgroundColor: '#333',
      padding: '1rem',
      marginBottom: '20px'
    }}>
      <div style={{
        display: 'flex',
        justifyContent: 'space-between',
        alignItems: 'center',
        maxWidth: '1200px',
        margin: '0 auto'
      }}>
        <Link 
          to="/" 
          style={{ 
            color: 'white', 
            textDecoration: 'none', 
            fontSize: '24px', 
            fontWeight: 'bold' 
          }}
        >
          My Blog
        </Link>
        
        <div style={{ display: 'flex', gap: '20px' }}>
          <Link 
            to="/" 
            style={{ color: 'white', textDecoration: 'none' }}
          >
            Home
          </Link>
          <Link 
            to="/blog" 
            style={{ color: 'white', textDecoration: 'none' }}
          >
            Blog
          </Link>
          <Link 
            to="/about" 
            style={{ color: 'white', textDecoration: 'none' }}
          >
            About
          </Link>
          <Link 
            to="/contact" 
            style={{ color: 'white', textDecoration: 'none' }}
          >
            Contact
          </Link>
        </div>
      </div>
    </nav>
  );
}

// Main App Component
function App() {
  return (
    <BrowserRouter>
      <div>
        <Navigation />
        
        <div style={{ maxWidth: '1200px', margin: '0 auto' }}>
          <Routes>
            <Route path="/" element={<HomePage />} />
            <Route path="/blog" element={<BlogPage />} />
            <Route path="/about" element={<AboutPage />} />
            <Route path="/contact" element={<ContactPage />} />
          </Routes>
        </div>
      </div>
    </BrowserRouter>
  );
}

export default App;

Key concepts demonstrated:

  • Link component: Creates navigation links that update the URL
  • Routes and Route: Define which component shows for each URL
  • Navigation stays consistent: The nav bar appears on every page
  • Clean URLs: /, /blog, /about, /contact

URL Parameters and Dynamic Routes#

Real apps often need dynamic routes based on data. Let's add individual blog post pages:

import { useParams } from 'react-router-dom';

// Blog post data (in real app, this would come from an API)
const blogPosts = {
  'react-basics': {
    title: 'Getting Started with React',
    date: '2024-01-15',
    content: `
      React is a powerful JavaScript library for building user interfaces. 
      In this comprehensive guide, we'll explore the fundamentals of React 
      development and build your first interactive component.
      
      ## Why React?
      
      React makes it easy to create interactive UIs by breaking them down 
      into reusable components. Each component manages its own state and 
      renders efficiently when data changes.
      
      ## Your First Component
      
      Let's start with a simple example...
    `
  },
  'javascript-guide': {
    title: 'Understanding JavaScript',
    date: '2024-01-10',
    content: `
      JavaScript is the backbone of modern web development. This guide 
      covers essential concepts every developer should master.
      
      ## ES6+ Features
      
      Modern JavaScript includes powerful features like arrow functions, 
      destructuring, and modules that make code more readable and maintainable.
      
      ## Asynchronous Programming
      
      Learn about Promises, async/await, and how to handle asynchronous 
      operations effectively...
    `
  },
  'css-tips': {
    title: 'CSS Tips and Tricks',
    date: '2024-01-05',
    content: `
      CSS is more powerful than ever! Let's explore modern techniques 
      that will elevate your styling game.
      
      ## Flexbox and Grid
      
      Master modern layout systems that make responsive design intuitive 
      and powerful.
      
      ## CSS Custom Properties
      
      Variables in CSS make theming and maintenance much easier...
    `
  }
};

function BlogPostPage() {
  const { postId } = useParams(); // Get the postId from the URL
  const post = blogPosts[postId];
  
  // Handle case where post doesn't exist
  if (!post) {
    return (
      <div style={{ padding: '20px', textAlign: 'center' }}>
        <h1>๐Ÿ˜• Post Not Found</h1>
        <p>The blog post you're looking for doesn't exist.</p>
        <Link to="/blog" style={{ color: '#0066cc' }}>
          โ† Back to Blog
        </Link>
      </div>
    );
  }
  
  return (
    <div style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}>
      <nav style={{ marginBottom: '30px' }}>
        <Link to="/blog" style={{ color: '#0066cc' }}>
          โ† Back to Blog
        </Link>
      </nav>
      
      <article>
        <header style={{ marginBottom: '30px' }}>
          <h1 style={{ fontSize: '2.5em', marginBottom: '10px' }}>
            {post.title}
          </h1>
          <p style={{ color: '#666', fontSize: '16px' }}>
            Published on {new Date(post.date).toLocaleDateString()}
          </p>
        </header>
        
        <div style={{ lineHeight: '1.6', fontSize: '18px' }}>
          {post.content.split('\\n\\n').map((paragraph, index) => {
            if (paragraph.startsWith('## ')) {
              return (
                <h2 key={index} style={{ 
                  marginTop: '40px', 
                  marginBottom: '20px',
                  fontSize: '1.5em'
                }}>
                  {paragraph.replace('## ', '')}
                </h2>
              );
            }
            return (
              <p key={index} style={{ marginBottom: '20px' }}>
                {paragraph}
              </p>
            );
          })}
        </div>
      </article>
      
      <footer style={{ 
        marginTop: '50px', 
        paddingTop: '30px', 
        borderTop: '1px solid #eee' 
      }}>
        <h3>Enjoyed this article?</h3>
        <p>
          <Link to="/contact" style={{ color: '#0066cc' }}>
            Get in touch
          </Link> to let me know what you'd like to read about next!
        </p>
      </footer>
    </div>
  );
}

// Update the App component to include the new route
function App() {
  return (
    <BrowserRouter>
      <div>
        <Navigation />
        
        <div style={{ maxWidth: '1200px', margin: '0 auto' }}>
          <Routes>
            <Route path="/" element={<HomePage />} />
            <Route path="/blog" element={<BlogPage />} />
            <Route path="/blog/:postId" element={<BlogPostPage />} />
            <Route path="/about" element={<AboutPage />} />
            <Route path="/contact" element={<ContactPage />} />
          </Routes>
        </div>
      </div>
    </BrowserRouter>
  );
}

New concepts:

  • URL Parameters: :postId in the route captures dynamic values
  • useParams hook: Extracts parameters from the current URL
  • Dynamic content: Same component shows different content based on URL
  • 404 handling: Show error message when content doesn't exist

Now URLs like /blog/react-basics will show the specific post!

Nested Routes and Layouts#

For complex applications, you often need nested routes. Let's create a dashboard section:

import { Outlet, useLocation } from 'react-router-dom';

// Dashboard Layout Component
function DashboardLayout() {
  const location = useLocation();
  
  const isActive = (path) => {
    return location.pathname === path;
  };
  
  return (
    <div style={{ display: 'flex', minHeight: '80vh' }}>
      {/* Sidebar Navigation */}
      <nav style={{
        width: '250px',
        backgroundColor: '#f8f9fa',
        padding: '20px',
        borderRight: '1px solid #ddd'
      }}>
        <h3 style={{ marginBottom: '20px' }}>Dashboard</h3>
        
        <div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
          <Link 
            to="/dashboard"
            style={{
              padding: '10px 15px',
              textDecoration: 'none',
              borderRadius: '5px',
              backgroundColor: isActive('/dashboard') ? '#0066cc' : 'transparent',
              color: isActive('/dashboard') ? 'white' : '#333'
            }}
          >
            ๐Ÿ“Š Overview
          </Link>
          
          <Link 
            to="/dashboard/analytics"
            style={{
              padding: '10px 15px',
              textDecoration: 'none',
              borderRadius: '5px',
              backgroundColor: isActive('/dashboard/analytics') ? '#0066cc' : 'transparent',
              color: isActive('/dashboard/analytics') ? 'white' : '#333'
            }}
          >
            ๐Ÿ“ˆ Analytics
          </Link>
          
          <Link 
            to="/dashboard/settings"
            style={{
              padding: '10px 15px',
              textDecoration: 'none',
              borderRadius: '5px',
              backgroundColor: isActive('/dashboard/settings') ? '#0066cc' : 'transparent',
              color: isActive('/dashboard/settings') ? 'white' : '#333'
            }}
          >
            โš™๏ธ Settings
          </Link>
          
          <Link 
            to="/dashboard/profile"
            style={{
              padding: '10px 15px',
              textDecoration: 'none',
              borderRadius: '5px',
              backgroundColor: isActive('/dashboard/profile') ? '#0066cc' : 'transparent',
              color: isActive('/dashboard/profile') ? 'white' : '#333'
            }}
          >
            ๐Ÿ‘ค Profile
          </Link>
        </div>
      </nav>
      
      {/* Main Content Area */}
      <main style={{ flex: 1, padding: '20px' }}>
        <Outlet /> {/* This renders the nested route content */}
      </main>
    </div>
  );
}

// Dashboard Page Components
function DashboardOverview() {
  return (
    <div>
      <h1>๐Ÿ“Š Dashboard Overview</h1>
      <p>Welcome to your dashboard! Here's a summary of your account.</p>
      
      <div style={{
        display: 'grid',
        gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))',
        gap: '20px',
        marginTop: '30px'
      }}>
        <div style={{
          backgroundColor: '#e3f2fd',
          padding: '20px',
          borderRadius: '8px',
          textAlign: 'center'
        }}>
          <h3>๐Ÿ“ Total Posts</h3>
          <p style={{ fontSize: '2em', margin: '10px 0' }}>23</p>
        </div>
        
        <div style={{
          backgroundColor: '#f3e5f5',
          padding: '20px',
          borderRadius: '8px',
          textAlign: 'center'
        }}>
          <h3>๐Ÿ‘€ Page Views</h3>
          <p style={{ fontSize: '2em', margin: '10px 0' }}>1,234</p>
        </div>
        
        <div style={{
          backgroundColor: '#e8f5e8',
          padding: '20px',
          borderRadius: '8px',
          textAlign: 'center'
        }}>
          <h3>๐Ÿ’ฌ Comments</h3>
          <p style={{ fontSize: '2em', margin: '10px 0' }}>89</p>
        </div>
      </div>
    </div>
  );
}

function DashboardAnalytics() {
  return (
    <div>
      <h1>๐Ÿ“ˆ Analytics</h1>
      <p>Detailed analytics about your blog performance.</p>
      
      <div style={{ marginTop: '30px' }}>
        <h3>Popular Posts</h3>
        <div style={{ marginTop: '15px' }}>
          {[
            { title: 'Getting Started with React', views: 456 },
            { title: 'Understanding JavaScript', views: 389 },
            { title: 'CSS Tips and Tricks', views: 267 }
          ].map((post, index) => (
            <div key={index} style={{
              display: 'flex',
              justifyContent: 'space-between',
              padding: '10px',
              borderBottom: '1px solid #eee'
            }}>
              <span>{post.title}</span>
              <span style={{ color: '#666' }}>{post.views} views</span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

function DashboardSettings() {
  const [settings, setSettings] = React.useState({
    emailNotifications: true,
    darkMode: false,
    autoSave: true
  });
  
  const handleToggle = (setting) => {
    setSettings(prev => ({
      ...prev,
      [setting]: !prev[setting]
    }));
  };
  
  return (
    <div>
      <h1>โš™๏ธ Settings</h1>
      <p>Customize your dashboard experience.</p>
      
      <div style={{ marginTop: '30px' }}>
        <h3>Preferences</h3>
        
        <div style={{ marginTop: '20px' }}>
          {Object.entries(settings).map(([key, value]) => (
            <div key={key} style={{
              display: 'flex',
              justifyContent: 'space-between',
              alignItems: 'center',
              padding: '15px 0',
              borderBottom: '1px solid #eee'
            }}>
              <span style={{ textTransform: 'capitalize' }}>
                {key.replace(/([A-Z])/g, ' $1').trim()}
              </span>
              <label style={{ cursor: 'pointer' }}>
                <input
                  type="checkbox"
                  checked={value}
                  onChange={() => handleToggle(key)}
                  style={{ marginRight: '10px' }}
                />
                {value ? 'Enabled' : 'Disabled'}
              </label>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

function DashboardProfile() {
  const [profile, setProfile] = React.useState({
    name: 'John Doe',
    email: 'john@example.com',
    bio: 'Web developer and blogger passionate about React and JavaScript.'
  });
  
  const handleChange = (e) => {
    setProfile({
      ...profile,
      [e.target.name]: e.target.value
    });
  };
  
  const handleSubmit = (e) => {
    e.preventDefault();
    alert('Profile updated! (This is just a demo)');
  };
  
  return (
    <div>
      <h1>๐Ÿ‘ค Profile</h1>
      <p>Manage your profile information.</p>
      
      <form onSubmit={handleSubmit} style={{ marginTop: '30px', maxWidth: '500px' }}>
        <div style={{ marginBottom: '20px' }}>
          <label style={{ display: 'block', marginBottom: '5px' }}>Name</label>
          <input
            type="text"
            name="name"
            value={profile.name}
            onChange={handleChange}
            style={{
              width: '100%',
              padding: '10px',
              border: '1px solid #ddd',
              borderRadius: '4px'
            }}
          />
        </div>
        
        <div style={{ marginBottom: '20px' }}>
          <label style={{ display: 'block', marginBottom: '5px' }}>Email</label>
          <input
            type="email"
            name="email"
            value={profile.email}
            onChange={handleChange}
            style={{
              width: '100%',
              padding: '10px',
              border: '1px solid #ddd',
              borderRadius: '4px'
            }}
          />
        </div>
        
        <div style={{ marginBottom: '20px' }}>
          <label style={{ display: 'block', marginBottom: '5px' }}>Bio</label>
          <textarea
            name="bio"
            value={profile.bio}
            onChange={handleChange}
            rows={4}
            style={{
              width: '100%',
              padding: '10px',
              border: '1px solid #ddd',
              borderRadius: '4px',
              resize: 'vertical'
            }}
          />
        </div>
        
        <button
          type="submit"
          style={{
            backgroundColor: '#0066cc',
            color: 'white',
            padding: '12px 24px',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Update Profile
        </button>
      </form>
    </div>
  );
}

// Update the main App component with nested routes
function App() {
  return (
    <BrowserRouter>
      <div>
        <Navigation />
        
        <div style={{ maxWidth: '1200px', margin: '0 auto' }}>
          <Routes>
            <Route path="/" element={<HomePage />} />
            <Route path="/blog" element={<BlogPage />} />
            <Route path="/blog/:postId" element={<BlogPostPage />} />
            <Route path="/about" element={<AboutPage />} />
            <Route path="/contact" element={<ContactPage />} />
            
            {/* Nested Dashboard Routes */}
            <Route path="/dashboard" element={<DashboardLayout />}>
              <Route index element={<DashboardOverview />} />
              <Route path="analytics" element={<DashboardAnalytics />} />
              <Route path="settings" element={<DashboardSettings />} />
              <Route path="profile" element={<DashboardProfile />} />
            </Route>
          </Routes>
        </div>
      </div>
    </BrowserRouter>
  );
}

// Don't forget to add Dashboard to the navigation!
function Navigation() {
  return (
    <nav style={{
      backgroundColor: '#333',
      padding: '1rem',
      marginBottom: '20px'
    }}>
      <div style={{
        display: 'flex',
        justifyContent: 'space-between',
        alignItems: 'center',
        maxWidth: '1200px',
        margin: '0 auto'
      }}>
        <Link 
          to="/" 
          style={{ 
            color: 'white', 
            textDecoration: 'none', 
            fontSize: '24px', 
            fontWeight: 'bold' 
          }}
        >
          My Blog
        </Link>
        
        <div style={{ display: 'flex', gap: '20px' }}>
          <Link to="/" style={{ color: 'white', textDecoration: 'none' }}>
            Home
          </Link>
          <Link to="/blog" style={{ color: 'white', textDecoration: 'none' }}>
            Blog
          </Link>
          <Link to="/dashboard" style={{ color: 'white', textDecoration: 'none' }}>
            Dashboard
          </Link>
          <Link to="/about" style={{ color: 'white', textDecoration: 'none' }}>
            About
          </Link>
          <Link to="/contact" style={{ color: 'white', textDecoration: 'none' }}>
            Contact
          </Link>
        </div>
      </div>
    </nav>
  );
}

Nested routing concepts:

  • Outlet component: Renders child route content inside parent layout
  • Index route: Default route for a parent (/dashboard shows overview)
  • Nested paths: /dashboard/analytics, /dashboard/settings, etc.
  • Layout sharing: Sidebar navigation appears on all dashboard pages

Programmatic Navigation#

Sometimes you need to navigate from JavaScript code, not just user clicks:

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

function LoginForm() {
  const navigate = useNavigate();
  const location = useLocation();
  const [credentials, setCredentials] = React.useState({
    username: '',
    password: ''
  });
  
  const handleSubmit = async (e) => {
    e.preventDefault();
    
    try {
      // Simulate login API call
      await new Promise(resolve => setTimeout(resolve, 1000));
      
      if (credentials.username === 'admin' && credentials.password === 'password') {
        // Successful login - redirect to dashboard or intended page
        const redirectTo = location.state?.from || '/dashboard';
        navigate(redirectTo, { replace: true });
      } else {
        alert('Invalid credentials');
      }
    } catch (error) {
      alert('Login failed');
    }
  };
  
  const handleChange = (e) => {
    setCredentials({
      ...credentials,
      [e.target.name]: e.target.value
    });
  };
  
  return (
    <div style={{ padding: '20px', maxWidth: '400px', margin: '50px auto' }}>
      <h1>๐Ÿ” Login</h1>
      <p>Please sign in to access your dashboard.</p>
      
      <form onSubmit={handleSubmit} style={{ marginTop: '30px' }}>
        <div style={{ marginBottom: '20px' }}>
          <label style={{ display: 'block', marginBottom: '5px' }}>
            Username
          </label>
          <input
            type="text"
            name="username"
            value={credentials.username}
            onChange={handleChange}
            placeholder="Try 'admin'"
            style={{
              width: '100%',
              padding: '10px',
              border: '1px solid #ddd',
              borderRadius: '4px'
            }}
          />
        </div>
        
        <div style={{ marginBottom: '20px' }}>
          <label style={{ display: 'block', marginBottom: '5px' }}>
            Password
          </label>
          <input
            type="password"
            name="password"
            value={credentials.password}
            onChange={handleChange}
            placeholder="Try 'password'"
            style={{
              width: '100%',
              padding: '10px',
              border: '1px solid #ddd',
              borderRadius: '4px'
            }}
          />
        </div>
        
        <button
          type="submit"
          style={{
            width: '100%',
            backgroundColor: '#0066cc',
            color: 'white',
            padding: '12px',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Login
        </button>
      </form>
      
      <div style={{ marginTop: '20px', textAlign: 'center' }}>
        <button
          onClick={() => navigate(-1)}
          style={{
            background: 'none',
            border: 'none',
            color: '#0066cc',
            cursor: 'pointer',
            textDecoration: 'underline'
          }}
        >
          โ† Go Back
        </button>
      </div>
    </div>
  );
}

// Example of a component that redirects after an action
function SuccessPage() {
  const navigate = useNavigate();
  
  React.useEffect(() => {
    // Redirect to home page after 3 seconds
    const timer = setTimeout(() => {
      navigate('/', { replace: true });
    }, 3000);
    
    return () => clearTimeout(timer);
  }, [navigate]);
  
  return (
    <div style={{ 
      padding: '20px', 
      textAlign: 'center',
      marginTop: '50px'
    }}>
      <h1>โœ… Success!</h1>
      <p>Your action was completed successfully.</p>
      <p>Redirecting to home page in 3 seconds...</p>
      
      <button 
        onClick={() => navigate('/')}
        style={{
          marginTop: '20px',
          backgroundColor: '#0066cc',
          color: 'white',
          padding: '10px 20px',
          border: 'none',
          borderRadius: '4px',
          cursor: 'pointer'
        }}
      >
        Go Home Now
      </button>
    </div>
  );
}

useNavigate features:

  • navigate('/path'): Go to a specific route
  • navigate(-1): Go back one page (like browser back button)
  • navigate(1): Go forward one page
  • replace: true: Replace current history entry instead of adding new one

Query Parameters and Search#

Handle URL query parameters for filtering and search:

import { useSearchParams } from 'react-router-dom';

function SearchableBlogPage() {
  const [searchParams, setSearchParams] = useSearchParams();
  const query = searchParams.get('q') || '';
  const category = searchParams.get('category') || 'all';
  
  const allPosts = [
    { id: 'react-basics', title: 'Getting Started with React', category: 'react', date: '2024-01-15' },
    { id: 'javascript-guide', title: 'Understanding JavaScript', category: 'javascript', date: '2024-01-10' },
    { id: 'css-tips', title: 'CSS Tips and Tricks', category: 'css', date: '2024-01-05' },
    { id: 'react-hooks', title: 'Mastering React Hooks', category: 'react', date: '2024-01-20' },
    { id: 'es6-features', title: 'Modern JavaScript Features', category: 'javascript', date: '2024-01-12' }
  ];
  
  // Filter posts based on search and category
  const filteredPosts = allPosts.filter(post => {
    const matchesQuery = query === '' || 
      post.title.toLowerCase().includes(query.toLowerCase());
    const matchesCategory = category === 'all' || post.category === category;
    return matchesQuery && matchesCategory;
  });
  
  const handleSearch = (e) => {
    const newQuery = e.target.value;
    setSearchParams(prev => {
      if (newQuery) {
        prev.set('q', newQuery);
      } else {
        prev.delete('q');
      }
      return prev;
    });
  };
  
  const handleCategoryChange = (newCategory) => {
    setSearchParams(prev => {
      if (newCategory !== 'all') {
        prev.set('category', newCategory);
      } else {
        prev.delete('category');
      }
      return prev;
    });
  };
  
  return (
    <div style={{ padding: '20px' }}>
      <h1>๐Ÿ“ Searchable Blog</h1>
      
      {/* Search and Filter Controls */}
      <div style={{ 
        marginBottom: '30px',
        padding: '20px',
        backgroundColor: '#f8f9fa',
        borderRadius: '8px'
      }}>
        <div style={{ marginBottom: '15px' }}>
          <input
            type="text"
            placeholder="Search posts..."
            value={query}
            onChange={handleSearch}
            style={{
              width: '100%',
              padding: '10px',
              border: '1px solid #ddd',
              borderRadius: '4px',
              fontSize: '16px'
            }}
          />
        </div>
        
        <div>
          <label style={{ marginRight: '15px' }}>Category:</label>
          {['all', 'react', 'javascript', 'css'].map(cat => (
            <button
              key={cat}
              onClick={() => handleCategoryChange(cat)}
              style={{
                marginRight: '10px',
                padding: '8px 16px',
                border: '1px solid #ddd',
                borderRadius: '4px',
                backgroundColor: category === cat ? '#0066cc' : 'white',
                color: category === cat ? 'white' : '#333',
                cursor: 'pointer',
                textTransform: 'capitalize'
              }}
            >
              {cat}
            </button>
          ))}
        </div>
      </div>
      
      {/* Results */}
      <div>
        <p style={{ color: '#666', marginBottom: '20px' }}>
          {filteredPosts.length} post{filteredPosts.length !== 1 ? 's' : ''} found
          {query && ' for "' + query + '"'}
          {category !== 'all' && ' in ' + category}
        </p>
        
        {filteredPosts.length === 0 ? (
          <div style={{ 
            textAlign: 'center', 
            padding: '40px',
            backgroundColor: '#f8f9fa',
            borderRadius: '8px'
          }}>
            <h3>๐Ÿ˜” No posts found</h3>
            <p>Try adjusting your search or filter criteria.</p>
          </div>
        ) : (
          <div>
            {filteredPosts.map(post => (
              <article key={post.id} style={{
                border: '1px solid #eee',
                padding: '20px',
                marginBottom: '20px',
                borderRadius: '8px'
              }}>
                <h2>
                  <Link 
                    to={'/blog/' + post.id}
                    style={{ color: '#333', textDecoration: 'none' }}
                  >
                    {post.title}
                  </Link>
                </h2>
                <div style={{ 
                  display: 'flex', 
                  justifyContent: 'space-between',
                  alignItems: 'center',
                  marginBottom: '10px'
                }}>
                  <span style={{
                    backgroundColor: '#e3f2fd',
                    color: '#1976d2',
                    padding: '4px 8px',
                    borderRadius: '12px',
                    fontSize: '12px',
                    textTransform: 'uppercase'
                  }}>
                    {post.category}
                  </span>
                  <span style={{ color: '#666', fontSize: '14px' }}>
                    {new Date(post.date).toLocaleDateString()}
                  </span>
                </div>
                <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit...</p>
                <Link to={'/blog/' + post.id} style={{ color: '#0066cc' }}>
                  Read more โ†’
                </Link>
              </article>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

Query parameter features:

  • useSearchParams: Hook to read and modify URL query parameters
  • searchParams.get('key'): Get a specific parameter value
  • setSearchParams: Update query parameters (updates URL automatically)
  • Bookmarkable searches: URLs like /blog?q=react&category=tutorials

404 Pages and Error Handling#

Handle routes that don't exist:

function NotFoundPage() {
  const navigate = useNavigate();
  
  return (
    <div style={{
      textAlign: 'center',
      padding: '50px 20px',
      maxWidth: '600px',
      margin: '0 auto'
    }}>
      <h1 style={{ fontSize: '6em', margin: '0' }}>404</h1>
      <h2>Page Not Found</h2>
      <p style={{ fontSize: '18px', color: '#666', marginBottom: '30px' }}>
        Oops! The page you're looking for doesn't exist. 
        It might have been moved, deleted, or you entered the wrong URL.
      </p>
      
      <div style={{ display: 'flex', gap: '15px', justifyContent: 'center' }}>
        <button
          onClick={() => navigate(-1)}
          style={{
            padding: '12px 24px',
            backgroundColor: '#6c757d',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          โ† Go Back
        </button>
        
        <Link
          to="/"
          style={{
            padding: '12px 24px',
            backgroundColor: '#0066cc',
            color: 'white',
            textDecoration: 'none',
            borderRadius: '4px',
            display: 'inline-block'
          }}
        >
          ๐Ÿ  Go Home
        </Link>
      </div>
      
      <div style={{ marginTop: '40px' }}>
        <h3>Popular Pages</h3>
        <div style={{ display: 'flex', flexDirection: 'column', gap: '10px', alignItems: 'center' }}>
          <Link to="/blog" style={{ color: '#0066cc' }}>๐Ÿ“ Blog</Link>
          <Link to="/about" style={{ color: '#0066cc' }}>๐Ÿ“– About</Link>
          <Link to="/contact" style={{ color: '#0066cc' }}>๐Ÿ“ง Contact</Link>
        </div>
      </div>
    </div>
  );
}

// Update the App component to include the 404 route
function App() {
  return (
    <BrowserRouter>
      <div>
        <Navigation />
        
        <div style={{ maxWidth: '1200px', margin: '0 auto' }}>
          <Routes>
            <Route path="/" element={<HomePage />} />
            <Route path="/blog" element={<SearchableBlogPage />} />
            <Route path="/blog/:postId" element={<BlogPostPage />} />
            <Route path="/about" element={<AboutPage />} />
            <Route path="/contact" element={<ContactPage />} />
            <Route path="/login" element={<LoginForm />} />
            <Route path="/success" element={<SuccessPage />} />
            
            <Route path="/dashboard" element={<DashboardLayout />}>
              <Route index element={<DashboardOverview />} />
              <Route path="analytics" element={<DashboardAnalytics />} />
              <Route path="settings" element={<DashboardSettings />} />
              <Route path="profile" element={<DashboardProfile />} />
            </Route>
            
            {/* Catch-all route for 404 */}
            <Route path="*" element={<NotFoundPage />} />
          </Routes>
        </div>
      </div>
    </BrowserRouter>
  );
}

Practice Exercise: Build a Product Catalog#

Create a product catalog with routing:

Requirements:

  1. Product list page with category filtering
  2. Individual product detail pages
  3. Shopping cart page
  4. Search functionality with URL parameters
  5. Breadcrumb navigation

Starter structure:

const products = [
  { id: 1, name: 'Laptop', category: 'electronics', price: 999 },
  { id: 2, name: 'T-Shirt', category: 'clothing', price: 29 },
  // Add more products...
];

function ProductCatalog() {
  // Your implementation here
  // Use useSearchParams for filtering
  // Link to individual product pages
}

function ProductDetail() {
  // Use useParams to get product ID
  // Show product details
  // Add to cart functionality
}

function ShoppingCart() {
  // Show cart items
  // Update quantities
  // Checkout flow
}

Router Best Practices#

1. Organize Routes Logically#

// โœ… Good - clear hierarchy
/blog
/blog/:postId
/dashboard
/dashboard/analytics
/dashboard/settings

// โŒ Bad - inconsistent structure
/blog
/post/:id
/user-dashboard
/analytics-page

2. Use Loading States#

function BlogPostPage() {
  const { postId } = useParams();
  const [post, setPost] = useState(null);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    fetchPost(postId).then(setPost).finally(() => setLoading(false));
  }, [postId]);
  
  if (loading) return <div>Loading...</div>;
  return <div>{/* post content */}</div>;
}

3. Handle Navigation States#

function Navigation() {
  const location = useLocation();
  
  return (
    <nav>
      <Link 
        to="/blog"
        className={location.pathname.startsWith('/blog') ? 'active' : ''}
      >
        Blog
      </Link>
    </nav>
  );
}

4. Use Breadcrumbs for Deep Navigation#

function Breadcrumbs() {
  const location = useLocation();
  const pathnames = location.pathname.split('/').filter(x => x);
  
  return (
    <nav>
      <Link to="/">Home</Link>
      {pathnames.map((name, index) => {
        const routeTo = '/' + pathnames.slice(0, index + 1).join('/');
        const isLast = index === pathnames.length - 1;
        
        return isLast ? (
          <span key={name}> / {name}</span>
        ) : (
          <span key={name}>
            {' / '}
            <Link to={routeTo}>{name}</Link>
          </span>
        );
      })}
    </nav>
  );
}

What We've Learned#

Congratulations! You now understand:

โœ… What React Router is and why it's essential for SPAs
โœ… Setting up routes with BrowserRouter, Routes, and Route
โœ… Navigation with Link components and programmatic navigation
โœ… URL parameters for dynamic content
โœ… Nested routes and layouts with Outlet
โœ… Query parameters for search and filtering
โœ… Error handling with 404 pages

Quick Recap Quiz#

Test your React Router knowledge:

  1. What component do you use to create navigation links?
  2. How do you access URL parameters in a component?
  3. What's the difference between Link and useNavigate?
  4. How do you create nested routes?

Answers: 1) Link component, 2) useParams hook, 3) Link is for user clicks, useNavigate is for programmatic navigation, 4) Use Outlet in parent and nested Route definitions

What's Next?#

In our next lesson, we'll learn about Protected Routes - how to add authentication and authorization to your React Router setup. You'll discover how to protect certain pages, redirect unauthorized users, and build secure navigation patterns.

React Router gives you the foundation, and protected routes add the security layer on top!

Previous

Protected Routes

Next

Conditional Rendering