Free React Course
For Beginners

L8 - Routing in React

React For Beginners by Itera

Key Points

  • A cup of theory
  • Install react router
  • Basic setup
  • Data Binding
  • Router guard

A cup of theory

Default way

One route - one physical page served from server

Changing the route leads to unload for the current page, and full load for the new page

Pros

  • Simplicity
  • Excellent control
  • Cache per page

Cons - User Experience

  • User loosing all data (or we need somehow to restore)
  • Reload take some time (even with cache)

The solution - use client routing

When URL changed - we are staying on the same physical page but the content refreshed by JS

This called - Single Page Application approach

A single-page application (SPA) is a web application or website that interacts with the user by dynamically rewriting the current web page, instead of the default method of a web browser loading entire new pages. The goal is faster transitions that make the website feel more like a native app - wikipedia

Router - key mechanism for SPA

Install react router

Current router version - 6

npm i react-router-dom

Basic setup

Features

  • Binding parameters
  • Nested routing
  • Multiple sets of routes

Add BrowserRouter

<BrowserRouter></BrowserRouter>;

BrowserRouter might be configured for serving from sub root

Add Routes

<BrowserRouter>
    <Routes>
    </Routes>
</BrowserRouter>;          

Routes container for a nested tree of elements that renders the branch that best matches the current location. React router supports multiple routes

Add list of routes

<BrowserRouter>
    <Routes>
        <Route path="/" element={<IndexPage />} />
        <Route path="/user" element={<UserPage />} />
    </Routes>
</BrowserRouter>;

When user will open default page - the Index page will be shown, when he will open /user, the UserPage will be shown

Declarative navigation

<Link to="/user">Go to user page</Link>

Programmatic navigation

const Forbidden = () => {
    const navigate = useNavigate();

    useEffect(() => {
        navigate("/");
    }, []);

    return <>FORBIDDEN</>;
};

Use useNavigate hook for programmatic navigation

OR a bit easier

const Forbidden = () => <Navigate to="/" />

BrowserRouter requires some backend setup as well

If this is not an option - use HashRouter, then your URL will be using hash to avoid querying backend http://localhost:3000/#/user/3

Data Binding

Data binding allows storing data which defines the page in the transferable manner, within the link

Real life example

https://twitter.com/drag137

Define

<Route path="/:userName" element={<UserPage />} />

Use

const UserPage = () => {
    const { userName } = useParams();
    return <div>Hello user: {userName}</div>;
};

We also can use userName or other similar parameter to fetch the data from backend

❗❗❗Important❗❗❗

Getting params inside the class-based component is not possible in react-router >=6

Router guard

Example

Imagine that you created a personal cabinet for the user. User have to login before visiting personal cabinet.

However, user might try to visit the cabinet without the authentication, using the direct link.

Thus, you need to guard it

Create the guard

type UserData = { user?: { authenticated: boolean } };

const UserPageGuard: FC<UserData> = ({ user }) =>
    user && user.authenticated ? 
    <UserPage /> : 
    <Navigate to="/login" />;

Update routes

<Routes>
    <Route path="/login" element={"Please login"} />
    <Route
        path="/:userName"
        element={<UserPageGuard user={userData} />}
    />
</Routes> 

Try to use

Now, if user is not authenticated, or no data is present, he will be automatically navigate to the login page

Nested routing

Why?

Imagine you created personal page for user: /user

Now you want to have two options of the view - default and posts but with the same layout

Then you might build your routing this way: default view withing /:user and posts view within /:user/posts

Add an outlet to the UserPage

const UserPage = () => {
    const { userName } = useParams();
    return (
        <>
            Hello user: {userName}
            <div>
                View: <Outlet></Outlet>
            </div>
        </>
    );
};

Outlet

Outlet - the "portal" where your sub-route will be rendered

Add Links to the default and post view

<div>
    <Link to="">Default view</Link>
</div>
<div>
    <Link to="posts">Posts view</Link>
</div>

Update routing

<Route path="/:userName" element={<UserPage/>}>
    <Route index element={"Default View"} />
    <Route path="posts" element={"Showing all posts"} />
</Route>

http://localhost:3000/drag13

            Hello user: drag13
            View: Default View
        

http://localhost:3000/drag13/posts

            Hello user: drag13
            View: Showing all posts
        

Full example is here

Another handy cases

  • Not found page
  • Optional parameters

Not found page

const AppApp = () => {
    return (
        <BrowserRouter>
        <Routes>
            <Route path="/" element={<HomePage />} />
            <Route path="*" element={<NotFoundPage />} />
        </Routes>
        </BrowserRouter>
    );
};
          

Optional parameters

const AppApp = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/user/:id" element={'userpage'} />
        <Route path="/user/" element={'userpage without id'} />
      </Routes>
    </BrowserRouter>
  );
};
          

Lazy loading

const LazyPage = lazy(() => import('./LazyPage'));

const AppApp = () => {
    return (
        <HashRouter>
            <Routes>
            <Route path="/" element={'DEFAULT'} />
            <Route path="/lazy" element={<LazyPage />} />
            </Routes>
        </HashRouter>
    );
};
            

Home task

  • Add header for your application
  • Create new page named `about`
  • Move all content related yourself to the page about
  • Add new query parameter named `ln` to your link like this: `https://8080?ln=ua`
  • If `ln` equals `ua` all texts should be in Ukrainian language
  • If `ln` equals `en` all text should be in English (feel free to use google translate if needed)

Useful links

Join me

Twitter
GitHub