React Router Interview Questions and Answers

Client side routing, BrowserRouter versus HashRouter, useParams, useNavigate, nested routes, protected routes and data loaders.

11 questions6 fresher, 4 mid-level, 1 senior

React has no built-in router, so every real app makes a routing decision, and interviewers use it to check that you understand what a single page app actually does to the browser. The question behind the question is usually: do you know that the URL is state, and that treating it as state solves problems you would otherwise solve badly.

1.What is React Router and why does React need a routing library?

Fresher

React renders components; it has no concept of a URL. React Router maps URLs to components and keeps the address bar, history and back button in sync while the page is never actually reloaded.

<BrowserRouter>
  <Routes>
    <Route path='/' element={<Home />} />
    <Route path='/products/:id' element={<Product />} />
    <Route path='*' element={<NotFound />} />
  </Routes>
</BrowserRouter>

It uses the History API to change the URL without a request, then renders the matching route. Frameworks such as Next.js and Remix ship their own routers built on the same idea, usually driven by the file system instead of a component tree.

Likely follow-up questions

  • Could you write a minimal router yourself?
Practise this in the quiz

2.What is the difference between client side routing and server side routing?

Mid-level

Server routing asks the server for a new HTML document on every navigation. Client routing intercepts the click, changes the URL with the History API and swaps components in place, so no document is fetched.

Server routingClient routing
Navigation costA full document request and parseA component swap, and maybe a data fetch
First loadFast: HTML arrives readySlower: the bundle must load first
StateLost on every navigationPreserved across navigations
NeedsNothing specialA server rewrite so deep links return the app shell

Likely follow-up questions

  • Why does refreshing a deep link 404 on a static host?
  • What does hybrid routing look like in Next.js?

3.What is the difference between BrowserRouter and HashRouter?

Fresher

BrowserRouter uses clean URLs through the History API and needs the server to serve the app for every path. HashRouter puts the route after a #, which the server never sees, so it works on any static host with no configuration.

  • BrowserRouter: /products/42. Clean, crawlable, requires a server rewrite.
  • HashRouter: /#/products/42. Works anywhere, but the fragment is never sent to the server, so no server rendering and weaker SEO.
  • MemoryRouter keeps history in memory with no URL at all, which is what you use in tests and in React Native.

Use BrowserRouter unless you are deploying somewhere you cannot configure, such as a legacy static host or a page embedded in another application.

Likely follow-up questions

  • Which one would you use inside an Electron app?

5.How do you read route parameters and query strings?

Fresher

useParams returns the dynamic segments of the matched path, and useSearchParams gives you a URLSearchParams object plus a setter for the query string.

// Route: /products/:id
const { id } = useParams();

const [searchParams, setSearchParams] = useSearchParams();
const page = Number(searchParams.get('page') ?? 1);
setSearchParams({ page: String(page + 1) });

Params are always strings, so convert and validate them. Keeping filters and pagination in the query string rather than in component state is the point worth making: it makes the view shareable, makes the back button correct, and survives a refresh for free.

Likely follow-up questions

  • Why keep filter state in the URL?
Practise this in the quiz

6.How do you navigate programmatically after an action?

Fresher

Call the function returned by useNavigate. Pass replace: true when the current entry should not stay in the history, such as after a successful login.

const navigate = useNavigate();

async function onSubmit(values) {
  const order = await createOrder(values);
  navigate(`/orders/${order.id}`, { replace: true });
}

navigate(-1); // back

Likely follow-up questions

  • When would you use replace?
Practise this in the quiz

7.What are nested routes, and what does Outlet do?

Mid-level

Nested routes let a parent route render shared layout and a child route render inside it. Outlet is the placeholder in the parent where React Router renders whichever child matched.

<Route path='/settings' element={<SettingsLayout />}>
  <Route index element={<Profile />} />
  <Route path='billing' element={<Billing />} />
</Route>

function SettingsLayout() {
  return (
    <div className='settings'>
      <SettingsNav />
      <Outlet />   {/* Profile or Billing renders here */}
    </div>
  );
}

The layout component stays mounted as you move between children, so its state, scroll position and any data it loaded survive the navigation. index marks the child shown at the parent's own path.

Likely follow-up questions

  • What does the index route mean?
Practise this in the quiz

8.How do you implement a protected route?

Mid-level

Wrap the routes in a component that checks authentication and either renders an Outlet or redirects to the login page, remembering where the user was trying to go.

function RequireAuth() {
  const { user, isLoading } = useAuth();
  const location = useLocation();

  if (isLoading) return <FullPageSpinner />;
  if (!user) return <Navigate to='/login' state={{ from: location }} replace />;

  return <Outlet />;
}

<Route element={<RequireAuth />}>
  <Route path='/dashboard' element={<Dashboard />} />
</Route>
  • Handle the loading state explicitly, or the user is bounced to login for a moment while the session is still being checked.
  • Use replace so the protected URL does not sit in the history behind the login page.
  • Keep the attempted location in state so you can send the user back there after signing in.

Likely follow-up questions

  • Is this secure?
  • How would you handle role based access?
Practise this in the quiz

9.How do you code split by route?

Mid-level

Wrap each route's component in React.lazy with a dynamic import and put a Suspense boundary above the routes, so each route's code downloads only when the user first visits it.

const Dashboard = lazy(() => import('./routes/Dashboard'));

<Suspense fallback={<RouteSkeleton />}>
  <Routes>
    <Route path='/dashboard' element={<Dashboard />} />
  </Routes>
</Suspense>

React Router's data routers can also declare a lazy route, which loads the component and its loader together. Either way, prefetch on hover or on link visibility if the navigation feels slow: the chunk is then usually already in cache by the time the user clicks.

Likely follow-up questions

  • How would you prefetch a route?
Practise this in the quiz

10.What are loaders and actions in React Router's data APIs?

Senior

A loader is a function attached to a route that fetches its data before the route renders; an action handles form submissions to that route. They move data fetching out of components and remove the render-then-fetch waterfall.

const router = createBrowserRouter([
  {
    path: '/products/:id',
    element: <Product />,
    loader: ({ params }) => fetchProduct(params.id),
    action: async ({ request }) => addToCart(await request.formData()),
    errorElement: <RouteError />,
  },
]);

function Product() {
  const product = useLoaderData();
}
  • Data fetching starts as soon as the navigation starts, in parallel with loading the route's code, instead of after the component mounts.
  • Nested route loaders run in parallel, so a layout and its child do not fetch one after the other.
  • errorElement gives each route its own error boundary, including for loader failures.
  • This is the same model Remix and the Next.js app router use, which is why it is worth knowing by name.

Likely follow-up questions

  • What is a fetch waterfall?
  • How does this compare to fetching in useEffect?

11.How do you handle a 404 and redirects?

Fresher

Add a catch-all route with path="*" for unmatched URLs, and render <Navigate to="..." replace /> for redirects. Order matters less in modern React Router because it ranks routes by specificity rather than by declaration order.

<Routes>
  <Route path='/' element={<Home />} />
  <Route path='/old-pricing' element={<Navigate to='/pricing' replace />} />
  <Route path='*' element={<NotFound />} />
</Routes>

Likely follow-up questions

  • Why is a client side redirect bad for SEO?

All React interview questions