React Router Helpers – Taking routing in React to the next level 🚀
Tags: react, reactrouterdom, reactrouterhelpers, reactrouterguads
Published: 2022-12-05 11:40:26


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ixy801yj22rvx3q0awgv.gif)

🤔 Imagine you are a Front-End React Engineer working at a [custom software development company](https://symfa.com/) or for your **mission impossible**, haha, **possible*** project, and you need to implement routing in your React application. The first thing that would immediately pop up in your mind would be using an **npm package** named **react-router-dom**, which is pretty much the standard way of doing it, right?


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8zt9z9kuhknat5tdtp15.gif)


However, do you sometimes feel there should be a much more efficient, secure, and simple way to implement route protection? Someway that improves how lazy components are loaded, so your app performance enhances? Or maybe there should be an easier way to debug the component loading lifecycle?


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d7fvdm9de2sq2ak0mo2x.gif)


Well, what if I tell you an **npm module** named **react-router-helper** provides simple, efficient, and quick-to-set-up ways of doing all of the above and much more? You might be thinking that it’s just another npm package that involves different and complicated syntax and involves much refactoring, right? It’s definitely not like that, the coolest part is that its syntax is super simple and it doesn’t require much change of code or refactoring.

**Cool features of react-router-helper package**
⬇️ Some cool features of this package include but are not limited to:
✔️ Adds Route protection.
✔️ Providing data for component pages.
✔️ Lazy component support out of the box.
✔️ If the user doesn’t have access to a certain component, then that component won’t even be loaded over the network.
✔️ It makes debugging and inspection into a loading component pretty easy by providing detailed statuses with hooks on each step of component loading.

## Simple setup
The setup of this package is pretty simple. All you need to do is:
👉 Install react-router-dom via your preferred package manager (npm/yarn).

For npm, **npm i react-router-dom**
For yarn, **yarn add react-router-dom**

👉 Install react-router-helpers via your preferred package manager (npm/yarn).

For npm, **npm i @symfa/react-router-helpers**
For yarn, **yarn add @symfa/react-router-helpers**

**Migration was never this easy!**
Imagine if you have an existing project codebase or the boilerplate template for adding a react-router-dom wrapped code layer and want to migrate to react-router-helper. The migration becomes super easy and happens without any major boilerplate code change except for swapping the tags with those used in react-router-helper if you’re using react-router-dom version 6 or above (Note: react-router-dom encourages its use with JavaScript objects ever since it’s version 6 was released because of much smoother and efficient experiences).


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/76w5tn8wv2nisbztct28.gif)

⬇️ Just follow the three steps mentioned below that demonstrate a code level before and after migration code, and you’re done with a complete migration:
🔯 Replace **useRoutes** tag with **useRoutesWithHelper**
**Before migration (react-router-dom version)**

```javascript
import { useRoutes } from 'react-router-dom';

function App() {
  let element = useRoutes([
    {
      path: '/',
      element: <Dashboard />,
      children: [
        {
          path: 'messages',
          element: <DashboardMessages />,
        },
        { path: 'tasks', element: <DashboardTasks /> },
      ],
    },
    { path: 'team', element: <AboutPage /> },
  ]);
  return element;
}
```

**After migration (react-router-helper version)**

```javascript
import { useRoutesWithHelper } from '@symfa/react-router-helpers';

function App() {
  let element = useRoutesWithHelper([
    {
      path: '/',
      element: <Dashboard />,
      children: [
        {
          path: 'messages',
          element: <DashboardMessages />,
        },
        { path: 'tasks', element: <DashboardTasks /> },
      ],
    },
    { path: 'team', element: <AboutPage /> },
  ]);
  return element;
}
```

🔯 Replace <**Outlet**/> with <**HelperOutlet**/>
**Before migration (react-router-dom version)**

```javascript
import { Outlet } from 'react-router-dom';

function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>
      
      <Outlet />
    </div>
  );
}
```

**After migration (react-router-helper version)**

```javascript
import { HelperOutlet } from '@symfa/react-router-helpers';

function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>

      <HelperOutlet />
    </div>
  );
}
```

🔯 Wrap your component into <**RouteHelper** /> if you are using **Route** and **component style**

**Before migration (react-router-dom version)**

```javascript
root.render(
  <BrowserRouter>
    <Routes>
      <Route path='/' element={<Dashboard />} />
    </Routes>
  </BrowserRouter>
);
```

**After migration (react-router-helper version)**

```javascript
import { RouteHelper } from '@symfa/react-router-helpers';

root.render(
  <BrowserRouter>
    <Routes>
      <Route path='/' element={<RouteHelper element={<Dashboard />} />} />
    </Routes>
  </BrowserRouter>
);
```

## Simple to use Architecture 
Do you often get panicked when you hear or learn about a complicated software technology architecture? Well, that’s **NOT** the case here because the entity structure of this amazing library is super simple.
 👉 There are only 3 entities involved which are mentioned and described below:
✏️ **Guard** (Provides protection to a page that a certain unauthorized user or a regular user cannot access, for example, the admin page).
🔎 Let’s explore a very basic usage example workflow:

You need to create the **guard function**.
 
```javascript
export const authorizationGuard = () => () => {
  return localStorage.getItem('token') !== null;
};
```

You need to import this **guard function** in the main App component and add it to the element object where you’ve defined the route you want to protect from unauthorized access. Yes, it’s that simple!

```javascript
import { useRoutesWithHelper } from '@symfa/react-router-helpers';

function App() {
  let element = useRoutesWithHelper([
    {
      path: '/',
      element: <Dashboard />,
      guards: [authorizationGuard],
    },
  ]);
  return element;
}
```

✏️ **Resolver** (Helps while a component is loading, usually when an API call request is in the process).
As a Frontend React Engineer, we often interact with the backend via Rest API calls or GraphQL since we need to load data from the server side on our react components. Ideally, what we use useEffect to make the API request call and use useState to indicate the loading data state so that our end-user can view some action, i.e., fetching data, in this case, is happening during that short time interval. This is exactly where the Resolver comes into play.

🔎 Let’s explore a very basic usage example workflow:
The first step always remains the same. Create a **resolver function**.

```javascript
export const userInfoResolver = () => async () => {
  const userInfo = await getUserInfo();
  
  return userInfo;
};
```

For basic level usage, this step again remains the same. You just need to import the **Resolver function** into the main App component and add it to the element object where you want it to be applied.

```javascript
import { useRoutesWithHelper } from '@symfa/react-router-helpers';

function App() {
  let element = useRoutesWithHelper([
    {
      path: '/',
      element: <Dashboard />,
      resolvers: {
        userInfo: userInfoResolver
      },
    },
  ]);
  return element;
}
```

Let’s also explore a scenario with the **Loading component**.

```javascript
import { useRoutesWithHelper } from '@symfa/react-router-helpers';

const Loading = () => {
  return <>Loading...</>;
};

function App() {
  let element = useRoutesWithHelper([
    {
      path: '/',
      element: <Dashboard />,
      loadingComponent: <Loading />,
      resolvers: {
        userInfo: userInfoResolver
      },
    },
  ]);
  return element;
}
```

You must be wondering that showing the component loading is fine but how do you receive and use the data returned by the resolvers, right? Well, that’s super simple to do. All you need to do is extract out or destructure the object using the **useResolver** hook and use it in your component.

```javascript
import { useResolver } from '@symfa/react-router-helpers';

export function Dashboard() {
  const { userInfo } = useResolver();
  
  return (<>
    <h2>Dashboard Page</h2>
    <h2>{userInfo.name}</h2>
  </>);
}
```

✏️ **Lazy component** (Provides out of the box support for lazy components).
This is one of the most special features of this library because lazy component usage has never been this smooth and efficient. 

👉 Following two features make it amazing:
1. No need for any additional wrapper such as **React.Suspense**.
2. Allows using guards to prevent the lazy component from loading. It means that if the user doesn’t have access to a lazy component page/component, that component won’t load. 


🔎 Let’s explore a very basic usage example workflow:
Let’s first explore a typical usage of lazy component with react-router-dom.

```javascript
import { useRoutes } from 'react-router-dom';
const Dashboard = React.lazy(() => import('./pages/Dashboard'));

function App() {
  let element = useRoutes([
    {
      path: '/',
      element: (
        <React.Suspense fallback={<>Loading</>}>
          <Dashboard />
        </React.Suspense>
      ),
    },
  ]);
  return element;
}
```

Now, let’s see a react-router-helper version of it.

```javascript
import { useRoutesWithHelper } from '@symfa/react-router-helpers';
const Dashboard = React.lazy(() => import('./pages/Dashboard'));

function App() {
  let element = useRoutesWithHelper([
    {
      path: '/',
      lazyElement: <Dashboard />,
    },
  ]);
  return element;
}
```
You might be wondering about how to use it with a loading component showing a loading indicator. Well, we’ve got that also covered for you.

```javascript
import { useRoutesWithHelper } from '@symfa/react-router-helpers';
const Dashboard = React.lazy(() => import('./pages/Dashboard'));

const LoadingComponent = () => <>Loading...</>;

function App() {
  let element = useRoutesWithHelper([
    {
      path: '/',
      lazyElement: <Dashboard />,
      loadingElement: <LoadingComponent />
    },
  ]);
  return element;
}
```

Similarly, you might come across use-cases where you need to validate against certain uncertain events or errors. A very relevant and common example in this case could be that for some uncertain reason(s), your internet connection got interrupted. 

❔ Now you might be thinking what to do in such a situation, right?
Well, just sit back and relax because our library got you covered with the help of **useLazyStatus** (used for providing detailed information about the lazy component status that can be received inside the **LoadingComponent** via the **useLazyStatus** hook) and **useLazyError** hook (used to provide detailed information about the error occurred while loading the lazy component).

🔎 Let’s explore a very basic usage example workflow:
Receiving lazy component statuses via the useLazyStatus hook.

```javascript
import { useLazyStatus } from '@symfa/react-router-helpers';

export const LoadingComponent = () => {
  const lazyStatus = useLazyStatus();

  useEffect(() => {
    console.log(lazyStatus);
  }, [lazyStatus]);

  return <>Loading...</>;
};
```

Now, let’s explore how to practically use the useLazyError hook to catch the lazy component error via the following code snippet.

```javascript
import { useLazyStatus, useLazyError } from '@symfa/react-router-helpers';

export const LoadingComponent = () => {
  const lazyStatus = useLazyStatus();
  const lazyError = useLazyError();

  useEffect(() => {
    console.log(lazyStatus);
  }, [lazyStatus]);

  useEffect(() => {
    console.log(useLazyError);
  }, [useLazyError]);

  return <>Loading...</>;
};
```

Looks pretty easy and straightforward, right? Well, that’s exactly how it is.

**Note**: You can explore further code snippets and further feature details about any of the entities from https://github.com/Aiscom-LLC/react-router-helpers#check-out-more-our-examples.


## Status indicators making debugging look very simple

Imagine if you wanted to know the status of any of these main entities, or are stuck somewhere trying to debug the cause of what’s going wrong. Debugging, in this case, would probably take a lot of your time. 

But here’s the cool thing about this library; it provides you with status messages for each entity so that you can easily get to know their status.

👉 There are four types of status mentioned below:
✔️ Initial – not initiated yet
✔️ Loading 
✔️ Loaded
✔️ Failed – couldn’t work for some reason.

🔎 Now, let’s explore how we would get the statuses:
Nothing complicated here as well, the common functional syntax pattern is **useEntityTypeStatus**.
1. To get guard statuses – **useGuardStatus**.
2. To get resolver statuses – **useResolverStatus**.
3. To get lazy component’s status – **useLazyStatus**.


In addition to these statuses, **LoadingComponent** is also used as a loading indicator. 

Routing in react was never so easy, and leveraging the routing features to their fullest makes react-router-helpers a decent library to look into when implementing routing in your React application.

**Happy routing!**