Photo by Aaron Burden on Unsplash
How to implement routing in reactJs without using react router package ?
Well, Today in this article we are going to discuss about one of the famous react interview question "How to implement routing in reactJs application without using router package for a very small application like 2 to 3 pages ? ".
So first of all lets create a new react application using npx create-react-app routing-app
This will create empty reactJs boiler plate code.
First thing that we are going to do is create a file name Routing.js
where we will page mapper. This will contain the name of all the screens that we are going to have. Something like this.
// Routing.js
export const pagesMapping = {
home:'home',
about:'about',
contact:'contact',
}
Now lets create a state which will keep our current selected page with the initial value of our first page which is home.
// Routing.js
const [page, setPage] = useState(pagesMapping.home);
When we are going to navigate from one page to other we will keep updating our page value using setPage for that this page and setPage need to be accessible in our complete application. To achieve that we are going to use React context api. Let's create it now.
// Routing.js
export const RoutingContext = createContext({ page: pagesMapping.home })
Now let's create context provider which will wrap our App.js
export default function AppRouter({children}) {
const [page, setPage] = useState(pagesMapping.home)
const value = useMemo(
() => ({ page, setPage }),
[page, setPage]
)
return (
<RoutingContext.Provider value={value}>
{children}
</RoutingContext.Provider>
)
}
In the above code we have passed the page state to the provider which will be accessible to our complete app once we wrap it in <App/>
inside index.js file. See below code.
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import Router from "./Routing";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<AppRouter>
<App />
</AppRouter>
</React.StrictMode>
);
Now let's create our pages inside App.js
and try to render it on the screen.
import logo from './logo.svg';
import './App.css';
import {pagesMapping, RoutingContext} from "./Routing";
import {useContext} from "react";
const Home = () => {
const { setPage } = useContext(RoutingContext)
const handleNavigation = () => {
setPage(pagesMapping.about)
}
return (
<div>
<h1>Home</h1>
<button onClick={handleNavigation}>GO TO ABOUT</button>
</div>
)
}
const About= () => {
return (
<div>
<h1>About</h1>
</div>
)
}
const Contact = () => {
return (
<div>
<h1>Contact</h1>
</div>
)
}
function App() {
const { page } = useContext(RoutingContext)
return (
<>
{(pagesMapping.home === page) && <Home />}
{(pagesMapping.about === page) && <About />}
{(pagesMapping.contact === page) && <Contact />}
</>
);
}
export default App;
Here in the above code i have created 3 pages which gets rendered on the screen. Once value of page
state gets updated. And to navigation from Home page to About page I have added a handleNavigation
function which update the page state using setPage
function. If you try to run this code it will work fine but wait a minute we are not getting url updated. Let's try to add that as well.
In the Routing.js
I have create an useEffect
hook which will update the url as well on the page value update. Let's see how
useEffect(() => {
window.history.pushState({ page }, '', `/${page}`);
const handlePopstate = (event) => {
const { page } = event.state || { page: 'home' };
setPage(page);
};
window.addEventListener('popstate', handlePopstate);
// Clean up the event listener on component unmount
return () => {
window.removeEventListener('popstate', handlePopstate);
};
}, [page]);
So in the above code when page state changes useEffect will get triggered which will update the url with this line of code window.history.pushState({page},'','/${page}');
Similarly when we are going to navigate back we are having an eventListener popstate
which will update the setPage with the previous page value on the url. This is how we will be able to update our page while moving back as well.
Here you can see complete code of Routing.js
import React, {useState, useMemo, createContext, useEffect} from 'react'
export const pagesMapping = {
home:'home',
about:'about',
contact:'contact',
}
export const RoutingContext = createContext({ page: pagesMapping.home })
export default function Router({ children }) {
/* Set the default page to Home if not specified otherwise in the URL */
const [page, setPage] = useState( pagesMapping.home)
const value = useMemo(
() => ({ page, setPage }),
[page, setPage]
)
useEffect(() => {
window.history.pushState({ page }, '', `/${page}`);
const handlePopstate = (event) => {
const { page } = event.state || { page: 'home' };
setPage(page);
};
window.addEventListener('popstate', handlePopstate);
// Clean up the event listener on component unmount
return () => {
window.removeEventListener('popstate', handlePopstate);
};
}, [page]);
return (
<RoutingContext.Provider value={value}>
{children}
</RoutingContext.Provider>
)
}