React Router Tutorial
People new to react generally don't know how to structure their routes.
Beginners and entry level developers will write something like this:
import "./App.css";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Profile from "./pages/Profile";
import Checkout from "./pages/Checkout";
import Login from "./pages/Login";
import Maps from "./pages/Maps";
import Settings from "./pages/Settings";
import Store from "./pages/Store";
const App = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/profile" element={<Profile />} />
<Route path="/checkout" element={<Checkout />} />
<Route path="/login" element={<Login />} />
<Route path="/maps" element={<Maps />} />
<Route path="/settings" element={<Settings />} />
<Route path="/store" element={<Store />} />
</Routes>
</BrowserRouter>
);
};
export default App;
Although this is acceptable for small projects, when your project scales - this will become incredibly difficult to read.
So we're going refactor the code into this:
import "./App.css";
import { BrowserRouter } from "react-router-dom";
import Router from "./pages/router";
const App = () => {
return (
<BrowserRouter>
<Router />
</BrowserRouter>
);
};
export default App;
It's cleaner, scalable and more readble. So let's get started!
Firstly create our React
app in typescript
by running the following commands in our terminal:
npx create-react-app router-tutorial --template typescript
cd router-tutorial
Create the Pages
We're only going to create two pages, Home
and About
.
Run the following commands in your terminal:
mkdir src/pages
mkdir src/pages/Home src/pages/About
touch src/pages/Home/index.tsx src/pages/About/index.tsx
What did we just do?
- Created
pages
directory. - Created two directories inside of
pages
:Home
andAbout
. - Created
index.tsx
files forHome
andAbout
.
Add this to your pages/About/index.tsx
file:
const About = () => {
return (
<div>
<h1>About</h1>
</div>
);
};
export default About;
Add this to your pages/Home/index.tsx
file:
const Home = () => {
return (
<div>
<h1>Home</h1>
</div>
);
};
export default Home;
This is pretty self explanatory, we've created two files which represent our pages.
Creating the types
Let create our types
by running the following commands in our terminal:
mkdir src/types
touch src/types/router.types.ts
Now add this to the newly created types/router.types.ts
file:
export interface routerType {
title: string;
path: string;
element: JSX.Element;
}
What is happening?
Declare a type for each route:
-
title
: this will be astring
-
path
: this will also be astring
-
element
: this will be aJSX.Element
Why declare types?
You'll see shortly that declaring the types will make sure each time we add a page object, it will follow a strict rule pattern and won't compile any errors.
Creating the Router
Now we're creating our router.
Run this command in your terminal:
touch src/pages/router.tsx src/pages/pagesData.tsx
Pages Data
Add to pages/pagesData.tsx
:
import { routerType } from "../types/router.types";
import About from "./About";
import Home from "./Home";
const pagesData: routerType[] = [
{
path: "",
element: <Home />,
title: "home"
},
{
path: "about",
element: <About />,
title: "about"
}
];
export default pagesData;
What is happening?
- We've imported our
pages
andtypes
. - Added a
title
,path
andelement
to each object.
Every time we want to add a new page, all we have to do is add a new page object into this array. The types will be strict so they must each contain a title
, path
and element
.
Router File
Add to pages/router.tsx
import { Route, Routes } from "react-router-dom";
import { routerType } from "../types/router.types";
import pagesData from "./pagesData";
const Router = () => {
const pageRoutes = pagesData.map(({ path, title, element }: routerType) => {
return <Route key={title} path={`/${path}`} element={element} />;
});
return <Routes>{pageRoutes}</Routes>;
};
export default Router;
What is happening?
We're mapping over the pagesData.tsx
file and for each object in our data, we are returning a route.
Update App File
Finally update the App.tsx
:
import "./App.css";
import { BrowserRouter } from "react-router-dom";
import Router from "./pages/router";
const App = () => {
return (
<BrowserRouter>
<Router />
</BrowserRouter>
);
};
export default App;
And we're all done! Thanks for reading.
Here is the Github repo.
Top comments (12)
What's the cleanest way to pass props into the route element in the pagesData.tsx file? This was the quick fix that VS Code applied, but it seems messy:
this will depend on the arguments of the *Blog *. If they are required I suggest:
This is much better, thanks! What would you suggest for redirects with this method? Say, for example, if I want to redirect the path from the default "/", to "/home".
You can do like this for less than v5 version
<Switch>
<Redirect exact from="/" to="/home"/>
</Switch>
Or for newest v6
<Route path="/" element={<Navigate to="/home" replace />} />
I really liked your article. Its a topic that needs to be talked about more.
Anyways my only thoughts were to make this lazy.
Then code-splitting can happen and we see big reductions in bundle sizes.
you can do it like this
const pagesData: routerType[] = [
{
path: "",
element: React.lazy(() => import('./Home')),
title: "home"
},
{
path: "about",
element: React.lazy(() => import('./About')),
title: "about"
}
];
Interesting way to structure it!
One thing i didn't understand. You changed format from JSX to an array of objects when you moved everything out off app.tsx. Combining that with splitting the code up in multiple files; doesn't that make it harder to read?
Hey Johan,
so actually this is the better practice as when you begin to scale the code it makes it more readable, for example if you have 100 routes for your site you can then begin to separate them like so
*Basic pages *
Advance Page
All routes
Now actually the update to react router (which is now v6) makes this format moot. Their new structure is basically the same as the one i've suggested here instead of the JSX format. This makes it more readable when scaling.
Nice way to separate the routes in a single file and organizate it. .
So we have created Types in this to use the routes, but how can we achieve it in javascript?
But how do you handle nested routes?
@kachiic You article helped me. This is how I used your solution for nested routes
router.jsx
pages.jsx
This way I can achieve multi-level nested routing...