<info 340/>
React Router
Joel Ross
Autumn 2023
View of the Day
-
React State Review (code reading)
-
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
- 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
- Has 1 feature almost implemented: Includes event handling and state manipulation
- 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 next week)
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:
- Find it! (via npm, google, etc). Read the documentation
- Install it!
npm install lib-name
- Import it!
import { ComponentName } from 'lib-name'
- (import structure may vary per library)
- 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 targeting:
Adds data apis (not using)
(other changes since then are mostly not relevant for us)
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:
-
The Base URI
- 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 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-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
next weeks
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!
Action Items!
-
Project Draft 2 due TOMORROW!!
-
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
info340au23-router
By Joel Ross
info340au23-router
- 177