<info 340/>

React Router

Joel Ross
Autumn 2022

View of the Day

  • Single Page Applications (lecture)

  • React Router (code demo)

  • URL Parameters (lecture + 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.

  • App is built: Ran create-react-app, etc. See assignment for details
  • ~90% of content rendered: "most" of your app should be there (main page at least, Components for everything else)
  • Has Components w/ props and data: Organize your Components! Can hard-code sample data for now
  • Has 1 feature almost implemented: Includes event handling and state manipulation
  • Fixing 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!)

Single-Page Applications

Our chat app so far...

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.

Install Library

Import Components

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

as of Nov 2021

Router Versions

The version we're using:

Adds data apis (not using)

BrowserRouter

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

//index.js

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

//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 />} />

      {/* 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() {
  return (
    <nav>
      <ul>
        <li>
          {/* replaces anchor element */}
    	  <Link to="home">Home</Link>
        </li>
        <li>
          <Link to="about">About</Link>
        </li>
      </ul>
    </nav>
  );
}

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) {
  render (
    <div className="user-layout">
      <h1>User Page</h1>
      <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>
  )
}

protocol

domain

resource

"Hi Wikipedia, I'd like you to send me the Informatics page!"

two

t
 

(how to handle info)

(who has info)

(what info you want)

Web Server

Response

Using the Internet

Request

Uniform Resource Indicator

http://www.domain.com/users => a list of users

  • The address is the identifier, the list is the resource

HTTP requests are sent to a particular resource on the web, identified by its URI (think: web address).

URI Format

Like postal addresses, URIs 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

Many web services allow you to access their data through their web API.


E.g., GitHub! (https://docs.github.com/en/rest)

https://api.github.com/users/your-github-name/repos

# command-line downloading
curl https://api.github.com/users/info201/repos

# authenticate (to see private repos)
curl -u username https://api.github.com/repos/info201/repos

# include headers
curl -i https://api.github.com/users/info201/repos

Example URIs (API)

Example URIs (API)

A web service's URI has two parts:

  1. The Base URI

     

  2. The EndPoint (e.g., path)

https://api.github.com

/users/{username}/repos

/repos/:owner/:repo

/emojis

A variable (also :username)

URL Params

Use :param syntax in the path to specify URL parameters. The useParams() hook lets you access the value of those parameter in 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-dom';

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

after the holiday

React Deployment to Firebase

Use a combination of firebase command line tools and create-react-app scripts to build and deploy your React application to Firebase hosting!

 

https://create-react-app.dev/docs/deployment/#firebase

Questions?

Action Items!

  • Project Draft 2 due Wednesday

  • Review Ch 17: React Router

  • Read Ch 18: AJAX Requests

    • ​(we'll apply to React in lecture)

  • Problem Set 08 due Monday (it's small)

  • Problem Set 09 due next week (it's small)


Next time: Working with Data: AJAX

info340au22-router

By Joel Ross

info340au22-router

  • 428