React Router

Joel Ross
Spring 2025

View of the Day

  • Single Page Applications (lecture)

  • React Router (code demo)

  • Firebase Hosting (demo)

Project Draft 2

What we are looking for: Refactored Draft 1 into a React App 

Converted the HTML/CSS from draft 1 into a published React app. Began to add interactive functionality.

  • ALL of content rendered: You should have Components that render DOM for every part of your page
  • Has Components w/ props and data: Organize your Components! Can hard-code sample data for now
  • Uses routes to show all page content (today!)
  • Has 1 feature implemented: Includes event handling and state manipulation (today). Can be the small feature!
  • Fixes issues from draft 1: You're revising the HTML/CSS, fix problems while you're at it!
  • Published to Firebase hosting: get that working this draft
    (see assignment for details; demo today!)
# switch to starter branch to get new starter code
git checkout starter

# download new starter code
git pull

# switch back to main branch for coding
git checkout main

# merge in new starter code (use default msg)
git merge starter --no-edit

# code and enjoy!

Get the starter code from the starter branch, but do all of your work on main.

Updating Lecture Code

Our chat app so far...

Single-Page Applications

Client-Side Routing

Render a different component depending on the URL.

"IF the current url MATCHES a route, render this Component!"

function App(props) {
  //pick a component based on the URL
  let componentToRender = null;
  if(currentUrl === '/home'){ //pseudocode comparison with URL
    componentToRender = <HomePage />;
  }
  else if(currentUrl === '/about'){
    componentToRender = <AboutPage />;
  }

  //render that component
  return <div>{componentToRender}</div>;
}

React Libraries

React components are structured to be self-contained, re-usable elements... so there are lots of pre-defined components online you can use!

In order to use a component in your app:

  1. Find it! (via npm, google, etc). Read the documentation
  2. Install it! npm install lib-name
  3. Import it! import { ComponentName } from 'lib-name'
    • (import structure may vary per library)
  4. Render it! <ComponentName />
    • Remember to pass any expected props!

react-router

A library of React Components that can determine which other components to render based on the current URL.

We are using this in declarative mode, not as a framework.

Install Library

Import Components

//in App.js
import { Routes, Route } from 'react-router';
# Install library (on command line)
npm install react-router

BrowserRouter

The BrowserRouter component will keep track of the current URL in its state, and re-renders descendent components if that changes.

/* in main.jsx */

import { BrowserRouter } from 'react-router'
import App from './components/App.jsx'

//render the App *inside* of the BrowserRouter
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

Routes

Pass elements in a Route Component to specify that they should only render when the URL matches a particular path. All routes go inside of a Routes element, which chooses which to "match" based on the URL

function App(props) {
  return (
    <Routes> {/* the collection of routes to match */}
      {/* if currentUrlPath === "home" */}
      <Route path="home" element={<HomePage />} />

      {/* else if currentUrlPath === "about" */}
      <Route path="about" element={<AboutPage />} />
    </Routes>
  );
}

Links

Use a Link element (in place of an <a>) to create state-based links between routes.

function Nav(props) {
  return (
    <nav>
      <ul>
        <li>
          {/* replaces anchor element */}
    	  <Link to="home">Home</Link>
        </li>
        <li>
          <Link to="about">About</Link>
        </li>
      </ul>
    </nav>
  );
}

URL Format

Like postal addresses, URLs follow a particular format.

  • scheme (protocol) how to access the information
  • domain which web service has the resource
  • path what resource to access
  • query extra parameters (arguments) to the request

format: ?key=value&key=value&key=value

Naming Routes

The web is based on the REST architecture. In this structure, each route (identifier, URI) should refer to a unique resource (set of information).

Think about what "information" should be found at each route. Come up with your routes first, and decide the components second!

function App(props) {
  return (
    <Routes>
      {/* good routes */}
      <Route path="/products" element={<AllProductsPage />} />
      <Route path="/products/hat" element={<HatPage />} />
      <Route path="/products/shoes" element={<ShoesPage />} />
      <Route path="/account" element={<AccountPage />} />
        
      {/* less good route -- an action, not a resource! */}
	  {/* (bad component definition as well) */}
      <Route path="/purchase" element={<ProcessPurchase />} />
    </Routes>
  )
}

Nesting Routes

The Route path corresponds to a segment of a URL, with nested Route elements corresponding to each segment. Nested Routes will render in place of an Outlet component

function App(props) {
  return (
    <Routes>
      <Route path="user" element={<UserLayout />} >
        <Route path="profile" element={<UserProfile />} />
        <Route path="favorites" element={<FavoriteItems />} />
      </Route>
      <Route path="items" element={<ItemList />} />
    </Routes>  
  );
}
function UserLayout(props) {
  return (
    <div className="user-layout">
      <h1>User Page</h1>
      <p>Layout specific content...</p>
      <Outlet /> {/* will be replaced with <UserProfile/>, etc */}
    </div>
  )
}

Protected Routes

A common use of nested routes is to make some routes protected, only showing content if e.g., the user is logged in.

function RequireAuth(props) {
  //...determine if user is logged in
  if(!userIsLoggedIn) { //if no user, say so
    return <p>Forbidden!</p>
  }
  else { //otherwise, show the child route content
    return <Outlet />
  }
}

function App(props) {
  return (
    <Routes>
      {/* protected routes */}
      <Route element={<RequireAuth />}>
        <Route path="profile" element={<ProfilePage />} />
        <Route path="secret" element={<SecretPage />} />
      </Route>
      {/* public routes */}
      <Route path="signin" element={<SignInPage />} />
    </Routes>
  )
}

"Variable" Routes

Sometimes you have a multiple routes that show the same component, just for different data--where that data is specified by one of the segments!

function App(props) {
  return (
    <Routes>
      <Route path="/products" element={<AllProductsPage />} />

      {/* routes go to same "view", just different content based on url */}
      <Route path="/products/hat" element={<ProductDetails item={"hat"} />} />
      <Route path="/products/shoes" element={<ProductDetails item={"shoes"} />} />

	</Routes>
  )
}

A url parameter is a "variable" in the url's path. This is a shortcut for defining a large number of routes that point to (similar) resources.

  • URL parameters are different than query params

URL Parameters

/users/:username

/users/:username/repos

/orgs/:owner/:repo

/users/{username}/repos

A variable

Two variables

Alternate notation

URL Params

Use :param syntax in the path to specify URL parameters. The useParams() hook lets you access the value of those parameters in the rendered element.

function App(props) {
  return (
    <Routes>
      {/* if currentUrl == "posts/______" */}
      {/* the string in the "blank" portion will be the
        * `postId` param */}
      <Route path="posts/:postId" element={<BlogPost />} />
    </Routes>
  );
}
import { useParams } from 'react-router';

function BlogPost(props) {
  const urlParams = useParams(); //access the URL params as an object
  const postId = urlParams.postId; //can use destructuring instead
    
  return (
    {/* postId was the URL parameter from above! */}
    <h1>You are looking at blog post {urlParams.postId}</h1>
  )
}

Hosting on Firebase

GitHub pages is not able to cleanly handle client-side routing, so we'll use Firebase to host your projects instead!

Firebase is a web backend solution; it provides multiple features which you can access without need to "code" them yourselves.

  • Web Hosting
  • Databases
  • User Authentication

next weeks

React Deployment to Firebase

Use a combination of Firebase command line tools and Vite scripts to build and deploy your React application to Firebase hosting!

 

See Project Draft 2 instructions on Canvas for details.

Action Items!

  • Complete task list for Week 8 (items 1-5 !!)

  • Problem Set 08 due Wednesday (​it is small)

  • Project Draft 2 due SUNDAY!!

 

Next time: React Review / Work Time

  • How would you like to use this time?

info340sp25-router

By Joel Ross

info340sp25-router

  • 10