If we want to navigate through our app internally, then we use Link. Link is similar to <a href but is used to open different page in our app and not external URLs like google.com
Let's say I am in Home page, / and I want to navigate to About page, /about then we can either type the /about in URL or use Link (when clicked will take us to /about page).
import { Link } from'react-router-dom'constHome= () => {return ( <sectionclassName="section"> <h2>Home Page</h2> <Linkto="/about"className="btn"> About </Link> </section> )}exportdefault Home
If we need to go to external URLs like google.com, then we still need to use <a href
Error Page
If we navigate to non-existing URL within our app then it shows a blank page by default which is not a good user experience. We can define a wildcard route (*) which goes to the page we say if none of the above routes match
import { BrowserRouter, Routes, Route } from'react-router-dom'import Home from'./pages/Home'import About from'./pages/About'import Error from'./pages/Error'functionApp() {return ( <BrowserRouter> <Routes> <Routepath="/"element={<Home />} /> <Routepath="about"element={<About />} /> // DEFAULT ROUTE IF ABOVE ROUTES DON'T MATCH <Routepath="*"element={<Error />} /> </Routes> </BrowserRouter> )}exportdefault App
import { Link } from'react-router-dom'constError= () => {return ( <sectionclassName="section"> <h1>404</h1> <h2>Page not found</h2> <Linkto="/"className="btn"> Back Home </Link> </section> )}exportdefault Error
Navbar
We want a navbar/ footer that will be common to all the pages (Home, about, and products). We can achieve it by
nesting these routes inside common path. For example, we want all routes to start at /
/
/about
/products
Once we nest them, we also need to use outlet section inside main route / so that this <Outlet/> will be either Home, Or About or Products
We need to know which link is selected, so we often add an active class. We can make use of NavLink provided by react-router-dom instead of Link. The difference is, the NavLink will show us if selected link is active or not.
Let's say we have products page that contains a list of products, and when we click on a product it will take us to details of individual product. We can make use of useParam() hook to see dynamically what ID is passed
App.js
functionApp() {return ( <BrowserRouter> <Routes> <Routepath="/"element={<SharedLayout />}> <Routeindexelement={<Home />} /> <Routepath="about"element={<About />} /> // These two routes below (products and it's id route can also be nested. Will see later how) <Routepath="products"element={<Products />} /> // this id will be passed as a parameter in url and we can know that id using useParam hook <Routepath="products/:productId"element={<SingleProduct />} /> <Routepath="*"element={<Error />} /> </Route> </Routes> </BrowserRouter> )}
import { Link, useParams } from'react-router-dom'import products from'../data'constSingleProduct= () => {// we get the dynamically passed parameter using useParams()const { productId } =useParams()return ( <sectionclassName="section product"> <h2>{productId}</h2> <Linkto="/products">back to products</Link> </section> )}exportdefault SingleProduct
Navigate (useNavigate)
Let's say we have a /login route that displays a login form, and when user logs in by filling creds, it should navigate us to Dashboard page. In Dashboard page, if user entered the creds, it should show "Hello, name", else it should display "Hello"
App.js
functionApp() {const [user,setUser] =useState(null)return ( <BrowserRouter> <Routes> <Routepath="/"element={<SharedLayout />}> <Routeindexelement={<Home />} /> <Routepath="about"element={<About />} /> // products and products/:productId could be nested (we will see how to do this later) <Routepath="products"element={<Products />} /> <Routepath="products/:productId"element={<SingleProduct />} /> <Routepath="login"element={<LoginsetUser={setUser} />} /> <Routepath="dashboard"element={<Dashboarduser={user} />} /> <Routepath="*"element={<Error />} /> </Route> </Routes> </BrowserRouter> )}
<Routepath="/"element={<SharedLayout />}> <Routeindexelement={<Home />} /> <Routepath="about"element={<About />} /> // products and products/:productId could be nested (we will see how to do this later) <Routepath="products"element={<Products />} /> <Routepath="products/:productId"element={<SingleProduct />} /> <Routepath="login"element={<LoginsetUser={setUser} />} /> <Routepath="dashboard"element={<Dashboarduser={user} />} /> <Routepath="*"element={<Error />} /> </Route></Routes>
Both of these routes "products" and "products/:productId" can be turned into nested route so that we know it is a group.
We do this similar to what we did in SharedLayout above.