Routing in full-stack development refers to the process of directing network requests from a client to the appropriate resources on a server or within a web application.
- Path Navigation: Routing manages how a web application responds to different URLs or paths requested by a client (usually a web browser).
- Client-Side and Server-Side Routing: In full-stack development, routing occurs both on the client side (in the browser) and the server side (on the server handling requests).
- Client-Side Routing: In client-side routing, the navigation and rendering of different views or components within a web application are handled by the browser. This often involves JavaScript frameworks like React, Angular, or Vue.js.
- Changing Views without Full Page Reload: Client-side routing enables seamless navigation within a web app by updating the URL and rendering content dynamically without reloading the entire page.
- Server-Side Routing: This refers to the process on the server that directs incoming requests to the appropriate resources or endpoints based on the requested URL.
- Handling API Endpoints: In server-side routing, requests to specific URLs or routes trigger different functions or controllers that process data, interact with databases, or perform other actions.
- Organizing Application Logic: Routing helps in organizing the application's structure by defining how different URLs correspond to various functionalities or views.
- Separation of Concerns: It promotes a separation of concerns, allowing developers to manage different parts of the application's functionality separately.
- Middleware Integration: Routing often involves the use of middleware, which intercepts requests, performs operations, or adds functionality before passing the request to the appropriate route handler.
- Security and Authorization: Middleware can be used in routing to enforce security measures, authentication, or authorization checks before allowing access to certain routes.
Navigation is an essential part of any user interface. In React, mapping URLs to specific views, components or pages is called routing.
Routing involves managing navigation from one view or component to another within a single-page application (SPA), without the need for traditional page reloads that you would see in multi-page websites. React itself doesn't come with built-in routing capabilities. Instead, routing is implemented using third-party libraries, with React Router being one of the most popular choices.
React Router is a declarative routing library for React, allowing you to create navigable components in your application. It enables the browser's history API to update the URL and keeps your UI in sync with the URL.
In a simple React application with React Router, you might have a layout with a navigation bar and several pages represented by components like Home
, About
, and Users
.
import {BrowserRouter as Router, Routes, Route, Link} from 'react-router-dom';
const App = () => {
return (
<Router>
<div>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/users">Users</Link></li>
</ul>
</nav>
{/* Define the routes */}
<Routes>
<Route path="/about" element={<About />} />
<Route path="/users" element={<Users />} />
<Route path="/" element={<Home />} />
</Routes>
</div>
</Router>
);
};
// Very simple view components
const Home = () => <h2>Home Page</h2>;
const About = () => <h2>About Page</h2>;
const Users = () => <h2>Users Page</h2>;
export default App;
- BrowserRouter: This component uses the HTML5 history API to keep your UI in sync with the URL. It should wrap your route definitions, usually at the root of your application. In this example, the
App
component wraps everything in a<Router>
to provide routing functionality. - Inside the
App
, a navigation bar is defined using<Link>
components to enable navigation without page reloads. - The
<Routes>
component contains multiple<Route>
components, each mapping a path to a component. - When the URL matches a path defined in one of the
<Route>
components, the corresponding component is rendered. For example, navigating to/about
will render the<About />
component.
The <Outlet>
component is part of React Router (version 6 and above) and serves as a placeholder for nested routes. It allows you to render child routes at a specific location within a parent component. This feature is particularly useful when creating layouts or sub-routes within your application, as it provides a way to compose your component hierarchy more dynamically.
When you define nested routes in React Router, the child route's component gets rendered where the parent route's component has an <Outlet>
. This means you can set up a common layout or structure in a parent component (like a navigation bar, sidebar, or footer), and use <Outlet>
to indicate where the child routes should be rendered within that structure.
Consider an application with a common layout for several sections, each with its own set of sub-pages. You can use <Outlet>
in the layout component to render these sub-pages.
First, define your routes with nesting:
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
const App = () => (
<Router>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<HomePage />} />
<Route path="about" element={<AboutPage />} />
<Route path="contact" element={<ContactPage />} />
{/* Add more nested routes as needed */}
</Route>
</Routes>
</Router>
);
Layout
is the parent component that includes the <Outlet>
, and HomePage
, AboutPage
, and ContactPage
are child routes that will be rendered inside Layout
where the <Outlet>
is placed.
Layout
component with <Outlet>
:
import { Outlet } from 'react-router-dom';
const Layout = () => (
<div>
<header>
{/* Navigation bar, logo, etc. */}
</header>
<main>
<Outlet /> {/* Child routes render here */}
</main>
<footer>
{/* Footer content */}
</footer>
</div>
);
<Outlet />
is placed within the <main>
tag. This setup means that when a user navigates to /about
, the AboutPage
component will be rendered inside the <main>
element of the Layout component, utilizing the same navigation bar and footer defined in Layout.
Benefits of Using Outlet:
- Simplifies Layout Management: Allows for a single, shared layout component for multiple routes, reducing redundancy and improving consistency across your application.
- Enhances Component Composition: Facilitates a more intuitive and hierarchical organization of components, making the component tree easier to manage and understand.
- Flexible Rendering: Nested routes can be easily adjusted or rearranged without major changes to the layout or parent components, offering greater flexibility in how content is presented.
Study: React Router Tutorial
-
Create a git branch
routing
based on the previous exercise and checkout to it. -
Install React Router:
npm install react-router-dom
-
Create a new folder
src/views
and move theHome
component to it. -
Create new components
Profile
,Upload
andSingle
and place them in thesrc/views
folder.- Add just some placeholder JSX to the components for now. (snippet:
rafcp
)
- Add just some placeholder JSX to the components for now. (snippet:
-
Create a
Layout
component insrc/components
folder. This is the shared layout for all views.- Add a navigation bar with Links to
Home
,Profile
andUpload
components. - Add a
<Outlet>
component to theLayout
component for rendering child routes/views.
<div> <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/profile">Profile</Link> </li> <li> <Link to="/upload">Upload</Link> </li> </ul> </nav> <main> <Outlet /> </main> </div>
- Add a navigation bar with Links to
-
In
App.jsx
, replace theHome
component withBrowserRouter
,Routes
andRoute
components.BrowserRouter
is imported asRouter
fromreact-router-dom
and wraps theRoutes
component.- import
Layout
, use it as a parentRoute
for the viewRoute
s - import all view components and add as
Route
s inside the parent layoutRoute
component. Route
path
props should match theto
props of theLink
components in theLayout
component.
import {Route, BrowserRouter as Router, Routes} from 'react-router-dom'; import Layout from './views/Layout'; import Home from './views/Home'; ... const App = () => { return ( <Router> <Routes> <Route element={<Layout />}> <Route path="/" element={<Home />} /> {/* TODO: add missing routes */} </Route> </Routes> </Router> ); };
-
Replace the
<dialog>
basedSingleView
component with theSingle
component inviews
folder.- Idea is to use router to display the
Single
component when a user clicks a media item in theMediaRow
component. - In
MediaRow
component, useLink
component istead of<button>
to navigate, item object can be passed asstate
prop to theLink
component:
<Link to="/single" state={{item}}>Show</Link>
- Idea is to use router to display the
-
Copy the JSX needed for displaying the media item from
components/SingleView.jsx
toviews/Single.jsx
and modify it to use theitem
fromuseLocation().state
instead ofselectedItem
state variable.import {useLocation} from "react-router-dom"; const Single = () => { const {state} = useLocation(); const item = state.item; ... // TODO: Return JSX for displaying a mediafile here ...
-
You can navigate back to listing with browser's back button or by using React Router's
useNavigate
hook with a button (more about hooks in the next week):import {NavigateFunction, useNavigate} from "react-router-dom"; ... const Single = () => { const navigate = useNavigate(); ... <button onClick={() => navigate(-1)}>Go back</button> ...
-
Check Building for Production
-
To fix the paths for
assets
and navigation in production build, set the public base path e.g. by addingbase
property tovite.config.js
:... export default defineConfig({ plugins: [react()], base: '/~your-username/routing/', });
Then add the same path to the
basename
prop of theRouter
component inApp.jsx
by reading it from the config:<Router basename={import.meta.env.BASE_URL}>
-
Run
npm build
ornpm run build
-
Copy contents of build folder (
dist/*
) to your home dir'spublic_html/wsk-routing/
(shell.metropolia.fi)- Can be done with scp tool in terminal:
scp -r dist/* [email protected]:~/public_html/wsk-routing/
- Can be done with scp tool in terminal:
-
Test your app: https://users.metropolia.fi/~your-username/wsk-routing/
-
Modify
README.md
. Add a text paragraph and link:Open [link text here](https://users.metropolia.fi/~your-username/wsk-routing/) to view it in the browser.
-
git add, commit & push current branch to the remote repository (GitHub)
-
Submit the link to correct branch of your repository to Oma