Index.js
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
Component BrowserRouter wraps the history object in the browser and passes it to down to component tree. Anywhere in the component tree we are able to use the history object. Then we need to register our routes in app.js.
app.js
import { Route, Redirect, Switch } from "react-router-dom";
class App extends Component {
render() {
return (
<div>
<NavBar />
<main className="container">
<Switch>
<Route path="/not-found" component={NotFound} />
<Route path="/register" component={RegisterForm} />
<Route path="/login" component={LoginForm} />
<Redirect from="/" exact to="/home" />
<Redirect to="/not-found" />
</Switch>
</main>
</div>
);
}
}
export default App;
If we did not use the "Switch", react would read "/" first and since that route is returning homepage, every route would return homepage too. For example,
<Route path="/register" component={RegisterForm} />
this would return "RegisterForm" and homepage. With using "Switch" we have to order our routers from most specific one to the most generic one. Means “/” should be in the bottom.
Now we have an issue. Every time we navigate from one page to another, we will have http requests from server. All of the components are part of the bundle and already downloaded when app loads so there is no need to reload them. Instead of reloading entire page with all assets, we should only update what we have in the content area. Solution is all the anchors should be replaced with “Link” from react-router-dom. Link component doesn't have “href” attr instead has “to”. Every time we click on links, “Link” has a click event. It will preventDefault(). So lets create a simple button with Link:
import { Link } from "react-router-dom";
<div className="col">
<Link to="/products/new" className="btn btn-primary my-2">
New Products
</Link>
</div>
In the beginning I said BrowserRouter wraps the history object in the browser and passes it to down to component tree. So we access it by "Route". When we registered our routes, "Route" automatically injects "History, Location, Match" props into the components. If you need to pass additional props to routed components; instead of component attribute we should use render attribute.
<Route path="/products" render={(props) => <Products sortBy= “newest” {...props} /> } />
Note that If we didnt pass “props”, History,Location and Match would disappear.
When user clicked on a button or submit a form, we wanna navigate it to a different page.
“History” object is responsible for navigation: go back, go forward, push and replace
PUSH: push method will add a new address in the browser history, so you click the back button and you go back to where you were.
REPLACE:replaces the current address, so we will not have history.
handleSave = ( ) => { this.props.history.push ("/products"); };
we can read route parameters and passed them to a component using the “match” object.
So we can render this info in our ProductDetails page as below.
<div>
<h2> productDetails-{this.props.match.params.id} </h2>
</div>
Query string parameters are in “location” object.