- Describe React Router's approach to client-side routing
- Explain how React Router allows building a route tree as a component
- Describe how routes are matched in React Router
So far, we have been building our applications without any navigation, so everything in the app has lived at the same URL. Currently, we can make it look like we are changing the page, by showing or hiding some components, but none of these changes are dependent on a change in the URL.
Now this may seem like a small quibble, but web addresses are the backbone of
the Internet. The web is just a series of links to other pages, after all. Let's
imagine that we have a React application hosted at www.loveforsoils.com
(not a
real website) dedicated to sharing knowledge about soil types. As a
facet of our React application, we want to provide users with the option to see
a list of our favorite soils. Currently, instead of sharing a link to a list of
our favorite soils, we can only provide a link to our "Love for soils" homepage.
Following which, users are required to interact with our application to see a
favorite soil list.
Because our personal opinion on the best soils is so important, we want to provide users with the opportunity to go straight to this list of the favorite soils view with a URL. Enter React Router: a routing library for React that allows us to link to specific URLs then show or hide various components depending on which URL is displayed. As React Router's documentation states:
Components are the heart of React's powerful, declarative programming model. React Router is a collection of navigational components that compose declaratively with your application. Whether you want to have bookmark-able URLs for your web app or a composable way to navigate in React Native, React Router works wherever React is rendering--so take your pick!
For this README we will be building our first Component routes as a code along.
Note: Make sure you clone down this repo, run npm install && npm start
, and open
http://localhost:3000
in the browser.
If you open up src/index.js
, you will see that currently we are defining
a Home
component, and then rendering that component in the DOM.
// ./src/index.js
import React from "react";
import ReactDOM from "react-dom";
const Home = () => {
return (
<div>
<h1>Home!</h1>
</div>
);
};
ReactDOM.render(<Home />, document.getElementById("root"));
With React Router our core routing will live in this component. We will define
our various routes within this file. To start using routes, we need to install
react-router-dom
:
$ npm install react-router-dom@5
Note: make sure to include @5
at the end of the install command to
install React Router version 5 instead of version 6.
To start implementing routes, we first need to import BrowserRouter
and
Route
from react-router-dom
. BrowserRouter
is commonly renamed as
Router
, so we'll follow this convention, as well. We can create an alias
with the syntax BrowserRouter as Router
. So every time we refer to Router
in
this file, we are really just referring to BrowserRouter
.
// .src/index.js
import React from "react";
import ReactDOM from "react-dom";
// Step 1. Import react-router functions
import { BrowserRouter as Router, Route } from "react-router-dom";
const Home = () => {
return (
<div>
<h1>Home!</h1>
</div>
);
};
// Step 2. Changed to have router coordinate what is displayed
ReactDOM.render(
<Router>
<Route path="/" component={Home} />
</Router>,
document.getElementById("root")
);
Step 1: In Step 1 above, there are two components that we are importing from React Router. We use them in turn.
Step 2: The Router
(our alias for BrowserRouter) component is the base for
our application's routing. It is where we declare how React Router will be
used. Notice that nested inside the Router
component we use the Route
component. The Route
component has two props in our example: path
and component
. The Route
component is in charge of saying: "when the URL
matches this specified path
, render this specified component
".
Let's try it. Copy the above code into src/index.js
and run npm start
to
boot up the application. Once it is running, point your URL to http://localhost:3000/
.
What you'll notice is that when you type in the URL it will render a
<div><h1>Home!</h1></div>
.
In the last two steps, we learned how to set up the basic Router
component
and inject our very first Route
component.
Next, we want to add components for About
and Login
:
// ./src/index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route } from "react-router-dom";
const Home = () => {
return (
<div>
<h1>Home!</h1>
</div>
);
};
const About = () => {
return (
<div>
<h1>This is my about component!</h1>
</div>
);
};
const Login = () => {
return (
<div>
<form>
<div>
<input type="text" name="username" placeholder="Username" />
<label htmlFor="username">Username</label>
</div>
<div>
<input type="password" name="password" placeholder="Password" />
<label htmlFor="password">Password</label>
</div>
<input type="submit" value="Login" />
</form>
</div>
);
};
Now let's add our /about
and /login
routes to our router:
// ./src/index.js
ReactDOM.render(
<Router>
<Route path="/" component={Home} />
<Route exact path="/about" component={About} />
<Route exact path="/login" component={Login} />
</Router>,
document.getElementById("root")
);
Reload your browser and look at our beautiful routes...oops! Error:
A `<Router>` may have only one child element
If you open up your browser dev tools console you should be seeing the same
error. What does this mean? Well, as you know in React, a component must return
one child/html node (which may wrap many others). We just gave Router
three
children! To remedy this problem we can place all of the Route
components
into a <div>
tag:
ReactDOM.render(
<Router>
<div>
<Route path="/" component={Home} />
<Route exact path="/about" component={About} />
<Route exact path="/login" component={Login} />
</div>
</Router>,
document.getElementById("root")
);
Let's go back to the browser and verify that our application is back to
functioning. We see that our Home
component is displaying. Try manually
typing in the URL locations for /
, /about
, and /login
. Do you see the
other components rendering?
You may have noticed the aberrant behavior of the Home
component. It is
always rendering, no matter which route we go to! Even if we type in nonsense
following the /
, we still get the Home
component.
Imagine we had a header we wanted displayed no matter which route was hit. In
that case, this behavior is desirable! Otherwise, there are several ways to fix
this. One way is to change our Route
component for Home
to exact path
instead of just path
.
<Route exact path="/" component={Home} />
Try it now.
-
We imported the
react-router-dom
node module into ourindex.js
with theBrowserRouter
asRouter
and theRoute
components -
We returned
Router
as the top level component in our React application -
We defined three possible routes, each of which is doing the following:
- defining what URLs to match on
- defining what component should be rendered, should a match return true
- setting an attribute of exact, which explicitly states that you will only see
the rendered component if you go to
/about
not/about/something_else
or/abo
.
We have made great progress so far!
If we look closely at our Route
s, we see that our 'components' being passed to
the component
prop are merely functions defined above that return JSX. If we
preferred, we could instead use the render
prop and write inline code directly
in our Route
:
<Route path="/" render={() => <h1>Home!</h1>} />
While this inline style may be useful for very simple renders, it becomes
unreasonable when we want to render larger, more complex components, but this
shows that we can be pretty flexible in how we set up our Route
s.
If you are interested in seeing the 'under the hood' differences between the
render
and the component
prop and when to use each take a moment to
familiarize yourself with the Route documentation.
Now that we have the tools to enable routing, let's look into how we can enable
users to trigger our Route
s without requiring a manual change of the address
bar.
What good are routes, if users don't know how to find them or what they are?
The React Router API provides two components that enable us to trigger our
routing: Link
and NavLink
. They both have the same base level functionality:
they update the browser URL and render the Route
component. NavLink
acts
as a superset of Link
, adding styling attributes to a rendered element when
it matches the current URL.
Let's work on adding in the NavLink
component to our application:
import React from "react";
import ReactDOM from "react-dom";
/* Add NavLink to importer */
import { BrowserRouter as Router, Route, NavLink } from "react-router-dom";
/* Add basic styling for NavLinks */
const link = {
width: "100px",
padding: "12px",
margin: "0 6px 6px",
background: "blue",
textDecoration: "none",
color: "white",
};
/* add the navbar component */
const Navbar = () => (
<div>
<NavLink
to="/"
/* set exact so it knows to only set activeStyle when route is deeply equal to link */
exact
/* add styling to Navlink */
style={link}
/* add prop for activeStyle */
activeStyle={{
background: "darkblue",
}}
>
Home
</NavLink>
<NavLink
to="/about"
exact
style={link}
activeStyle={{
background: "darkblue",
}}
>
About
</NavLink>
<NavLink
to="/login"
exact
style={link}
activeStyle={{
background: "darkblue",
}}
>
Login
</NavLink>
</div>
);
const Home = () => <h1>Home!</h1>;
const About = () => <h1>This is my about component!</h1>;
const Login = () => (
<form>
<h1>Login</h1>
<div>
<input type="text" name="username" placeholder="Username" />
<label htmlFor="username">Username</label>
</div>
<div>
<input type="password" name="password" placeholder="Password" />
<label htmlFor="password">Password</label>
</div>
<input type="submit" value="Login" />
</form>
);
ReactDOM.render(
<Router>
<div>
<Navbar />
<Route exact path="/" component={Home} />
<Route exact path="/about" component={About} />
<Route exact path="/login" component={Login} />
</div>
</Router>,
document.getElementById("root")
);
Load up the browser again and you should see beautiful blue <NavLink>
components that load up the desired component. For more practice, implement
/signup
and /messages
using <Route>
s and <NavLink>
s that load in
components.
In anticipation of a growing codebase, let's refactor by removing the components
we defined in index.js
and placing them in their own files in src/
.
Additionally, let's change them to classic class React.Component
s, i.e.:
// src/Home.js
import React from "react";
class Home extends React.Component {
render() {
return <h1>Home!</h1>;
}
}
export default Home;
// src/About.js
import React from "react";
class About extends React.Component {
render() {
return <h1>This is my about component!</h1>;
}
}
export default About;
// src/Login.js
import React from "react";
class Login extends React.Component {
render() {
return (
<form>
<h1>Login</h1>
<div>
<input type="text" name="username" placeholder="Username" />
<label htmlFor="username">Username</label>
</div>
<div>
<input type="password" name="password" placeholder="Password" />
<label htmlFor="password">Password</label>
</div>
<input type="submit" value="Login" />
</form>
);
}
}
export default Login;
// src/Navbar.js
import React from "react";
import { NavLink } from "react-router-dom";
const link = {
width: "100px",
padding: "12px",
margin: "0 6px 6px",
background: "blue",
textDecoration: "none",
color: "white",
};
class Navbar extends React.Component {
render() {
return (
<div>
<NavLink
to="/"
/* set exact so it knows to only set activeStyle when route is deeply equal to link */
exact
/* add styling to Navlink */
style={link}
/* add prop for activeStyle */
activeStyle={{
background: "darkblue",
}}
>
Home
</NavLink>
<NavLink
to="/about"
exact
style={link}
activeStyle={{
background: "darkblue",
}}
>
About
</NavLink>
<NavLink
to="/login"
exact
style={link}
activeStyle={{
background: "darkblue",
}}
>
Login
</NavLink>
</div>
);
}
}
export default Navbar;
// src/index.js
import React from "react";
import ReactDOM from "react-dom";
import Home from "./Home";
import About from "./About";
import Login from "./Login";
import Navbar from "./Navbar";
import { BrowserRouter as Router, Route } from "react-router-dom";
ReactDOM.render(
<Router>
<div>
<Navbar />
<Route exact path="/" component={Home} />
<Route exact path="/about" component={About} />
<Route exact path="/login" component={Login} />
</div>
</Router>,
document.getElementById("root")
);
react-components-as-routes's People
Forkers
thejasonfile benjaminhenriquez drzackyll liahwallace1 briod itzsaga mikeries shalstein davidtom dkennell srosenshine kwebster2 carakane mgoldfi1 lofiandcode adamlarosa kat-star noamsauerutley lizbur10 learn-co-students assansav chrisbaptiste83 bonjourannie munroe1786 ericiscoding chriskay25 antheam melindadiaz07 acparkgh jmlovitsch kylefarmer85 h11z laurencun i-am-lain joshua-flatiron zackcarlson014 mikesap gooseisdead brynknowles artwilton dickm19 jayelle0 liamh47 mkirby billyott stacksonstack myildiz17 see-bet-code sagbeyeg bjf-flatiron skanagui noble-webb jinastrickland caseyokay jomariepolanco mkoenke dyson1602 jzolo22 victorsloop jonnyhak warrenniu jlorda aru120 techtwin hugodelgado18 kguerra96 jaquan1314 nnhk23 patriciaarnedo stephenvincentibanez saief124 sarabastian wlytle jcface marisayou tolentinoel gamil91 alexriosdev metrio jpeterson14 jacobkagon purisquiri crrojas88 raaynaldo dbrisco93 jetechny stevenwutg jbondeson19 will-gon alecgrey iizzylca hukic-m denaweiss5 sampassarelli marcia-free hamoose18 chippychoppy tbustama racross1 alexanderbowersreact-components-as-routes's Issues
Spelling error
"Load up the browser again and you should see beautiful blue navlinks that load up the desired component. To get more comfortable, I would recommend implementing /signup and /messages routes that load in compnents, also make sure to add in some NavLinks."
should be components
Link Broken === no love for soil ?
npm ERR! notarget It was specified as a dependency of 'cosmiconfig'
This lesson had a dependency that used require-from-string, an NPM package published by floatdrop, who recently deleted his NPM account, taking all his NPM packages with it. Currently, there is a work around by directly installing the package from his github using the following command in the lesson root directory:
npm install https://github.com/floatdrop/require-from-string/tarball/v1.1.0 --save
npm install
This codealong is showing up as a lab
Update for React Router v6
- Change install instructions for v5
- Update links for v5
Confusing instructions
First the lesson says to do this:
"In anticipation of a growing codebase, let's refactor by removing the components we defined in index.js and placing them in their own files in src/."
Then we are given instructions that assume that you did NOT do the above:
"Let's work on adding in the component to our application. For ease of display, we will work as if we still have all of our components in one file. If you have broken them out into individual component files, update accordingly:"
I commented out the files I just created, but that part seems like an unnecessary detour.
Thank you.
grammar error
Change: "passing a arrow function inside of a render"
To: "passing an arrow function inside of a render
grammar error
duplicate "only" in code comment below:
/* set exact so it knows only to only set activeStyle when route is deeply equal to link */
Is it Navbar or NavBar?
This is a reading
This is a readme; it should not be looking for you to fork or pass tests
No console error thrown where error expected as per code along directions
No error thrown, app compiles correctly and does not throw any console errors as expected by code along instructions:
"Following, let's add our /about and /login routes to our router:
// ./src/index.js
ReactDOM.render((
<Router>
<Route path="/" render={Home} />
<Route exact path="/about" render={About} />
<Route exact path="/login" render={Login} />
</Router>),
document.getElementById('root')
);
Reload your browser and look at our beautiful routes...oops! Error:
A may have only one child element"
Lab won't go away
I have completed the lab and committed it with the green submitted your work showing and I then click the blue I'm done button and the Next Lesson button but it always jumps back to being at the stage of clicking the blue I'm done button. This is the only lab I have in the whole course I cannot complete and it is keeping React from being 100% complete. I would Love if someone could help me resolve this.
Erroneous and Error-producing Code Block in Example
In the introduction of NavLinks
, within the first illustrative code example that defines and assigns const Navbar
all of the <NavLink/>
s as a whole should be wrapped in a return
statement. (line 17)
The other examples further along in this lesson however appear to be correct.
No test to be run
Can't get the green light due to no test in the code along! Sad day!
Typo?
The Route component has two props in our example:
path
andrender
I think render
should be component
in this example.
navlinks section was removed
in previous version before most recent overhaul. move into part 2
Can't get `npm start` to run due to issues with package.json
I've spent thirty minutes trying to get npm start
to run, and it just keeps giving me different errors about dependencies. I've tried running npm install
npm audit fix
npm update
and deleting the package-lock.json file. I can't get get anything to work.
Here's an example of the error messages I'm seeing:
❯ npm start
> [email protected] start /Users/helloamandamurphy/Development/code/Labs/react-components-as-routes-v-000
> react-scripts start
There might be a problem with the project dependency tree.
It is likely not a bug in Create React App, but something you need to fix locally.
The react-scripts package provided by Create React App requires a dependency:
"babel-loader": "8.0.6"
Don't try to install it manually: your package manager does it automatically.
However, a different version of babel-loader was detected higher up in the tree:
/Users/helloamandamurphy/Development/code/Labs/react-components-as-routes-v-000/node_modules/babel-loader (version: 6.4.1)
Manually installing incompatible versions is known to cause hard-to-debug issues.
If you would prefer to ignore this check, add SKIP_PREFLIGHT_CHECK=true to an .env file in your project.
That will permanently disable this message but you might encounter other issues.
To fix the dependency tree, try following the steps below in the exact order:
1. Delete package-lock.json (not package.json!) and/or yarn.lock in your project folder.
2. Delete node_modules in your project folder.
3. Remove "babel-loader" from dependencies and/or devDependencies in the package.json file in your project folder.
4. Run npm install or yarn, depending on the package manager you use.
In most cases, this should be enough to fix the problem.
If this has not helped, there are a few other things you can try:
5. If you used npm, install yarn (http://yarnpkg.com/) and repeat the above steps with it instead.
This may help because npm has known issues with package hoisting which may get resolved in future versions.
6. Check if /Users/helloamandamurphy/Development/code/Labs/react-components-as-routes-v-000/node_modules/babel-loader is outside your project directory.
For example, you might have accidentally installed something in your home folder.
7. Try running npm ls babel-loader in your project folder.
This will tell you which other package (apart from the expected react-scripts) installed babel-loader.
If nothing else helps, add SKIP_PREFLIGHT_CHECK=true to an .env file in your project.
That would permanently disable this preflight check in case you want to proceed anyway.
P.S. We know this message is long but please read the steps above :-) We hope you find them helpful!
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] start: `react-scripts start`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/helloamandamurphy/.npm/_logs/2019-12-16T22_25_04_019Z-debug.log
I've also tried manually updating the packages and can't get through all of them.
As always, there's a chance it's user error, but I haven't seen this message before.
some confusing things about this walkthrough
There's a couple of things that seem to be a little out of order/need tweaking.
There's this code snipet that is explained afterwards:
// .src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
// Step 1. Import react-router functions
import { BrowserRouter as Router, Route } from 'react-router-dom';
const App = () => {
return (
<div>
<h1>Home</h1>
</div>
);
};
// Step 2. Changed to have router coordinate what is displayed
ReactDOM.render((
<Router>
<Route path="/" component={App} />
</Router>),
document.getElementById('root')
);
The description then goes on to say:
We are using the render prop in the Route component, but we could have used component={Home} instead. With render we are just invoking a function call to render <div><h1>Home</h1></div>.
The issue is when you talk about using the render prop in the Route component.
Then he next code snipet is:
// ./src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route } from 'react-router-dom';
const App = () => {
return (
<div>
<Router>
<Route exact path="/" render={() => <h1>Home</h1>} />
</Router>
</div>
);
};
ReactDOM.render(
<App />,
document.getElementById('root')
);
It seems to me that this code snipet is the one the first one should be. ?
Also later on in the walkthrough there's this:
NAVLINKS
What good are routes, if users don't know how to find them or what they are?
The React Router API comes with two options of adding in Links: and . The both have the same base level functionality...
This seems unclear as to what the two options for adding links are.
@BriOD originally posted here: learn-co-students/react-components-as-routes-v-000#12 (comment)
@Lukeghenco is this something you might be able to take a look at?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.