Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
294 views

React Router

React Router is a standard routing library for React that manages URLs and keeps the application UI and URL in sync. It allows single-page applications to render views inline without reloading the page. React Router uses a declarative approach where routes are defined as components and the router renders the appropriate component based on the current URL path. It keeps track of navigation history using the history object, which changes the current location using methods like push and replace.

Uploaded by

Yesmine Makkes
Copyright
© © All Rights Reserved
Available Formats
Download as ODT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
294 views

React Router

React Router is a standard routing library for React that manages URLs and keeps the application UI and URL in sync. It allows single-page applications to render views inline without reloading the page. React Router uses a declarative approach where routes are defined as components and the router renders the appropriate component based on the current URL path. It keeps track of navigation history using the history object, which changes the current location using methods like push and replace.

Uploaded by

Yesmine Makkes
Copyright
© © All Rights Reserved
Available Formats
Download as ODT, PDF, TXT or read online on Scribd
You are on page 1/ 13

Introduction

React Router is the standard routing library for React. When you need to navigate through a React
application with multiple views, you’ll need a router to manage the URLs. React Router does that,
keeping your application UI and the URL in sync.
One of the main features of React is that it allows the creation of single-page applications (SPAs)
that are rendered on the client side. A SPA might have multiple views (aka pages), and unlike the
conventional multi-page apps, navigating through these views shouldn’t result in the entire page
being reloaded. Instead, we want the views to be rendered inline within the current page. The end
user, who’s accustomed to multi-page apps, expects the following features to be present in an SPA:
• Each view in an application should have a URL that uniquely specifies that view. This is so
that the user can bookmark the URL for reference at a later time — e.g.
www.example.com/products.
• The browser’s back and forward button should work as expected.
• The dynamically generated nested views should preferably have a URL of their own too —
e.g. www.example.com/products/shoes/101, where 101 is the product id.

Routing is the process of keeping the browser URL in sync with what’s being rendered on the page.
React Router lets you handle routing declaratively. The declarative routing approach allows you to
control the data flow in your application, by saying “the route should look like this”:
<Route path="/about" component={About}/>

You can place your <Route> component anywhere that you want your route to be rendered. Since
<Route>, <Link> and all the other React Router API that we’ll be dealing with are just
components, you can easily get used to routing in React.
A note before getting started. There’s a common misconception that React Router is an official
routing solution developed by Facebook. In reality, it’s a third-party library that’s widely popular for
its design and simplicity. If your requirements are limited to routers for navigation, you could
implement a custom router from scratch without much hassle. However, understanding how the
basics of React Router will give you better insights into how a router should work.
n this SuperSkill we'll cover 4 main topics. First, we’ll be setting up React and React Router using
npm. Then we’ll jump right into React Router basics. You’ll find different code demonstrations of
React Router in action. The examples covered include:
• Basic navigational routing
• Nested routing
• Nested routing with path parameters
• Protected routing
Let’s get started!
Setting up React Router
Let's assume you already have a development environment up and running. Where you've used
Create React App to generate the files required for creating a basic React project. The default
directory structure generated by Create React App should look something like this:
react-routing-v4-superskill
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
└── src
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
└── serviceWorker.js

The React Router library comprises three packages: react-router, react-router-dom,


and react-router-native. react-router is the core package for the router, whereas the
other two are environment-specific. You should use react-router-dom if you’re building a
website, and react-router-native if you’re on a mobile app development environment
using React Native.
Let's use npm to install react-router-dom:
npm install --save react-router-dom

react-router:
provides the core
routing
components and functions for the React Router applications.
react-router-native:
is used for mobile applications.
react-router-dom:
is used for web applications design.

React Router Basics


Here’s an example of how our routes will look:

<Router>
<Route exact path="/" component={Home} />
<Route path="/category" component={Category} />
<Route path="/login" component={Login} />
<Route path="/products" component={Products} />
</Router>

Router
You need a router component and several route components to set up a basic route as exemplified
in the previous screen. Since we’re building a browser-based application, we can use two types of
routers from the React Router API:
1. <BrowserRouter>
2. <HashRouter>

The primary difference between them is evident in the URLs that they create:
// <BrowserRouter>
http://example.com/about

// <HashRouter>
http://example.com/#/about

Router
The <BrowserRouter> is more popular amongst the two because it uses the HTML5 History
API to keep track of your router history. The <HashRouter>, on the other hand, uses the hash
portion of the URL (window.location.hash) to remember things. If you intend to support
legacy browsers, you should stick with <HashRouter>.

Wrap the <BrowserRouter> component around the App component.

In index.js:
/* Import statements */
import React from 'react';
import ReactDOM from 'react-dom';

/* App is the entry point to the React code.*/


import App from './App';

/* import BrowserRouter from 'react-router-dom' */


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

ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
, document.getElementById('root'));

Note: A router component can only have a single child element. The child element can be an HTML
element — such as div — or a react component.
For the React Router to work, you need to import the relevant API from the react-router-dom
library. Here We’ve imported the BrowserRouter into index.js. We’ve also imported the
App component from App.js. App.js, as you might have guessed, is the entry point to React
components.
The above code creates an instance of history for our entire App component.
Let's now formally introduce you to history...
<BrowserRouter>
keeps track of router's history using the HTML5
History
API.
<HashRouter>
keeps track of router's history using the hash portion of the URL. The <BrowserRouter/> and the
<HashRouter/> are two
component
exported from
react-router-dom

history
history is a JavaScript library that lets you easily manage session history anywhere JavaScript
runs. history provides a minimal API that lets you manage the history stack, navigate, confirm
navigation, and persist state between sessions. — React Training docs
Each router component creates a history object that keeps track of the current location
(history.location) and also the previous locations in a stack. When the current location
changes, the view is re-rendered and you get a sense of navigation. How does the current location
change? The history object has methods such as history.push() and history.replace()
to take care of that. history.push() is invoked when you click on a <Link> component, and
history.replace() is called when you use <Redirect>. Other methods — such as
history.goBack() and history.goForward() — are used to navigate through the
history stack by going back or forward a page.
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route } from "react-router-dom";

ReactDOM.render(
<Router>
<div>
<Route exact path="/">
<Home />
</Route>
<Route path="/news">
<NewsFeed />
</Route>
</div>
</Router>,
node
);
Links and Routes
• The <Route> component is the most important component in React router. It renders some UI if
the current location matches the route’s path. Ideally, a <Route> component should have a prop
named path, and if the pathname is matched with the current location, it gets rendered.

• The <Link> component, on the other hand, is used to navigate between pages. It’s comparable to
the HTML anchor element. However, using anchor links would result in a browser refresh, which
we don’t want. So instead, we can use <Link> to navigate to a particular URL and have the view
re-rendered without a browser refresh.
Link
is used to navigate amongst the
internal routes
in our router application. It is the equivalent of anchor tags: <a> </a>. It's passed a string argument
‘to’
where the URL’s path is specified. The
<Route>
will return null in case the specified
URL
doesn’t match the defined
path
. The basic <Route> takes two arguments, one for path and one for rendering
UI

Demo 1: Basic Routing


We’ve covered everything you need to know to create a basic router. Let’s build one:
src/App.js
/* Import statements */
import React, { Component } from 'react';
import { Link, Route } from 'react-router-dom';

/* Home component */
const Home = () => (
<div>
<h2>Home</h2>
</div>
)

/* Category component */
const Category = () => (
<div>
<h2>Category</h2>
</div>
)

/* Products component */
const Products = () => (
<div>
<h2>Products</h2>
</div>
)

/* App component */
const App = () =>{
return (
<div>
<nav className="navbar navbar-light">
<ul className="nav navbar-nav">

/* Link components are used for linking to other views */


<li><Link to="/">Homes</Link></li>
<li><Link to="/category">Category</Link></li>
<li><Link to="/products">Products</Link></li>

</ul>
</nav>

/* Route components are rendered if the path prop matches the current
URL */
<Route path="/" component={Home}/>
<Route path="/category" component={Category}/>
<Route path="/products" component={Products}/>

</div>
)
}

Demo 1: Basic Routing


We’ve declared the components for Home, Category and Products inside App.js. Although this is
okay for now, when the component starts to grow bigger, it’s better to have a separate file for each
component. As a rule of thumb, we usually create a new file for a component if it occupies more
than 10 lines of code. (Starting from the second demo, we’ll be creating a separate file for
components that have grown too big to fit inside the App.js file).

Inside the App component, we’ve written the logic for routing. The <Route>‘s path is matched
with the current location and a component gets rendered. The component that should be rendered is
passed in as a second prop.
Here / matches both / and /category. Therefore, both the routes are matched and rendered.
How do we avoid that? We should pass the exact= {true} props to the router with
path='/':
<Route exact={true} path="/" component={Home}/>

If you want a route to be rendered only if the paths are exactly the same, you should use the exact
props.
We use exact={true} to impose further restrictions on path matching.True
The Route component exists in react modules False

In which path the login component will appear: /login/login/person


<Route path="/login" component={Login} />
Nested Routing
To create nested routes, we need to have a better understanding of how <Route> works. Let’s do
that.
<Route> has three props that you can you use to define what gets rendered:

• component. We’ve already seen this in action. When the URL is matched, the router creates
a React element from the given component using React.createElement.
• render. This is handy for inline rendering. The render prop expects a function that returns an
element when the location matches the route’s path.
• children. The children prop is similar to render in that it expects a function that returns a
React element. However, children gets rendered regardless of whether the path is matched
with the location or not.

Switch Component
Before we head for the demo code, let's introduce you to the <Switch> component.
When multiple <Route>s are used together, all the routes that match are rendered inclusively.
Consider this code from demo 1. We’ve added a new route to demonstrate why <Switch> is
useful.
<Route exact path="/" component={Home}/>
<Route path="/products" component={Products}/>
<Route path="/category" component={Category}/>
<Route path="/:id" render = {()=> (<p> I want this text to show up for all
routes other than '/', '/products' and '/category' </p>)}/>

If the URL is /products, all the routes that match the location /products are rendered. So, the
<Route> with path :id gets rendered along with the Products component. This is by design.
However, if this is not the behavior you’re expecting, you should add the <Switch> component to
your routes. With <Switch>, only the first child <Route> that matches the location gets
rendered.
Your Answer
Knowing that switch checks each route for a match sequentially and stops once the first match is
found. How would you tactically order the path ‘users/:id’ and ‘users’ to have a correct match each
time:
<switch>
<route path="/users/:id" component={User}/>
<route path="/users" component={Roster}/>
</switch>

Demo 2: nested routing


Earlier on, we created routes for /, /category and /products. What if we wanted a URL of
the form /category/shoes?

src/App.js
import React from 'react';
import { Link, Route, Switch } from "react-router-dom";
import Category from "./Category";

const App = () => {


return (
<div>
<nav className="navbar navbar-light">
<ul className="nav navbar-nav">
<li>
<Link to="/">Homes</Link>
</li>
<li>
<Link to="/category">Category</Link>
</li>
<li>
<Link to="/products">Products</Link>
</li>
</ul>
</nav>

<Switch>
<Route exact path="/" component={Home} />
<Route path="/category" component={Category} />
<Route path="/products" component={Products} />
</Switch>
</div>
);
};

export default App;

<
Route
path
={`${match.
path
}/:name`} render= {({match}) =>( <div> <h3> {
match
.
params
.name} </h3></div>)}/>

Demo 3: Nested routing with Path parameters


Let’s complicate things a bit more, shall we? A real-world router will have to deal with data and
display it dynamically. Assume that we have the product data returned by a server API of the form
below.
src/Products.jsx
const productData = [
{
id: 1,
name: 'NIKE Liteforce Blue Sneakers',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin
molestie.',
status: 'Available'
},
{
id: 2,
name: 'Stylised Flip Flops and Slippers',
description: 'Mauris finibus, massa eu tempor volutpat, magna dolor euismod
dolor.',
status: 'Out of Stock'

},
{
id: 3,
name: 'ADIDAS Adispree Running Shoes',
description: 'Maecenas condimentum porttitor auctor. Maecenas viverra
fringilla felis, eu pretium.',
status: 'Available'
},
{
id: 4,
name: 'ADIDAS Mid Sneakers',
description: 'Ut hendrerit venenatis lacus, vel lacinia ipsum fermentum vel.
Cras.',
status: 'Out of Stock'
},

];

We need to create routes for the following paths:


• /products. This should display a list of products.
• /products/:productId. If a product with the :productId exists, it should display
the product data, and if not, it should display an error message.
src/Products.jsx
/* Import statements have been left out for code brevity */

const Products = ({ match }) => {

const productsData = [
{
id: 1,
name: 'NIKE Liteforce Blue Sneakers',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Proin molestie.',
status: 'Available'

},

//Rest of the data has been left out for code brevity

];
/* Create an array of `<li>` items for each product
var linkList = productsData.map( (product) => {
return(
<li>
<Link to={`${match.url}/${product.id}`}>
{product.name}
</Link>
</li>
)
})

return(
<div>
<div>
<div>
<h3> Products</h3>
<ul> {linkList} </ul>
</div>
</div>

<Route path={`${match.url}/:productId`}
render={ (props) => <Product data= {productsData} {...props} />}/>
<Route exact path={match.url}
render={() => (
<div>Please select a product.</div>
)}
/>
</div>
)
}

First, we created a list of <Links>s using the productsData.ids and stored it in linkList.
The route takes a parameter in the path string which corresponds to that of the product id.
<Route path={`${match.url}/:productId`}
render={ (props) => <Product data= {productsData} {...props} />}/>

You may have expected component = { Product } instead of the inline render function.
The problem is that we need to pass down productsData to the Product component along with
all the existing props. Although there are other ways you can do this, we find this method to be the
easiest. {...props} uses the ES6’s spread syntax to pass the whole props object to the
component.
Here’s the code for Product component:
src/Product.jsx
/* Import statements have been left out for code brevity */

const Product = ({match,data}) => {


var product= data.find(p => p.id == match.params.productId);
var productData;

if(product)
productData = <div>
<h3> {product.name} </h3>
<p>{product.description}</p>
<hr/>
<h4>{product.status}</h4> </div>;
else
productData = <h2> Sorry. Product doesnt exist </h2>;

return (
<div>
<div>
{productData}
</div>
</div>
)
}
The find method is used to search the array for an object with an id property that equals
match.params.productId. If the product exists, the productData is displayed. If not, a
“Product doesn’t exist” message is rendered.
<
Route
exact
path
={`${match.
url
}/:
productId`
} render={ (props) => <Product data= {productsData} {...props} />}/>

Protecting Routes
For the final demo, we’ll be discussing techniques concerning protecting routes. So, if someone
tries to access /admin, they’d be required to log in first. However, there are some things we need to
cover before we can protect routes.

Redirect
Like the server-side redirects, <Redirect> will replace the current location in the history stack
with a new location. The new location is specified by the to prop. Here’s how we’ll be using
<Redirect>:
<Redirect to={{pathname: '/login', state: {from: props.location}}} />

So, if someone tries to access the /admin while logged out, they’ll be redirected to the /login
route. The information about the current location is passed via state, so that if the authentication is
successful, the user can be redirected back to the original location. Inside the child component, you
can access this information at this.props.location.state.

Custom Routes
A custom route is a fancy word for a route nested inside a component. If we need to make a
decision whether a route should be rendered or not, writing a custom route is the way to go.
Here’s the custom route declared among other routes.
src/App.js
/* Add the PrivateRoute component to the existing Routes */
<Switch>
<Route exact path="/" component={Home} data={data}/>
<Route path="/category" component={Category}/>
<Route path="/login" component={Login}/>
<PrivateRoute authed={fakeAuth.isAuthenticated} path='/products' component =
{Products} />
</Switch>
fakeAuth.isAuthenticated returns true if the user is logged in and false otherwise.

Custom Routes
Here’s the definition for PrivateRoute:
src/App.js
/* PrivateRoute component definition */
const PrivateRoute = ({component: Component, authed, ...rest}) => {
return (
<Route
{...rest}
render={(props) => authed === true
? <Component {...props} />
: <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
/>
)
}

The route renders the Admin component if the user is logged in. Otherwise, the user is redirected to
/login. The good thing about this approach is that it is evidently more declarative and
PrivateRoute is reusable.

Custom Routes
Finally, here’s the code for the Login component:
src/Login.jsx
const Login = props => {
const [redirectToReferrer, setRedirectToReferrer] = useState(false);

const login = () => {


fakeAuth.authenticate(() => setRedirectToReferrer(true));
};

const { from } = props.location.state || { from: { pathname: "/" } };

if (redirectToReferrer) {
return <Redirect to={from} />;
}

return (
<div>
<p>You must log in to view the page at {from.pathname}</p>
<button onClick={login}>Log in</button>
</div>
);
};
export const fakeAuth = {
isAuthenticated: false,
authenticate(cb) {
this.isAuthenticated = true;
setTimeout(cb, 100);
}
};

The line below demonstrates object destructuring, which is a part of the ES6 specification.
const { from } = this.props.location.state || { from: { pathname: '/' } }

The custom routes are predefined in reactFalse


The redirect component replace the current location in the history stackTrue
Private routes are used to make some components only visible to the right user
True

Recap
React Router is a powerful library that complements React for building better, declarative routes.
Unlike the prior versions of React Router, in v4, everything is “just components”. Moreover, the
new design pattern perfectly fits into the React way of doing things.
We've covered:
• how to setup and install React Router
• the basics of routing and some essential components such as <Router>, <Route> and
<Link>
• how to create a minimal router for navigation and nested routes
• how to build dynamic routes with path parameters

You might also like