All about NextJS routing
Published: 2022-04-25 02:34:17

## Intro

- It has a file-system based routing mechanism
- When a file is added to the pages folder in a project, it automatically becomes available as a route
- By mixing and matching file names with a nested folder structure, it is possible to pretty much define the most common routing patterns
- Routing variations are: 
    - Route with pages
    - Nested routes
    - Dynamic routes
    - Catch-all routes
    - Navigate from the UI
    - Programmatically navigate between pages

### Routing with pages
It has a file-system-based routing mechanism.

1. Scenario 01: index.js file within the pages folder will map to the root (https://localhost:3000) of your domain. 
2. Scenario 02: Pages are associated with routes based on their names. In the pages folder, **about.js** maps to https://localhost:3000/about and **profile.js** maps to https://localhost:3000/profile in the address bar.

### Nested routes

1. Scenario 01: **pages->blog->index.js** maps to https://localhost:3000/blog
2. Scenario 02: **pages->blog->first.js** maps to https://localhost:3000/blog/first
3. Scenario 03: **pages->blog->second.js** maps to https://localhost:3000/blog/second

### Dynamic routes

- To implement dynamic routes, you need to name a component by wrapping it with square brackets like **[componentName].js** and **componentName** will correspond to the dynamic value in the **url**
- **pages->product->[productId].js** maps to https://localhost:3000/product/1, https://localhost:3000/product/2 or even https://localhost:3000/product/100. The number/string after the **/product/** in the **url** will dynamically correspond and map to **[productId].js** component and the number/string after **/product/** can be found inside **[productId].js** component using the **useRouter** hook like this - 

```js 
 const router = useRouter();
    const productId = router.query.productId; 
    // productId is the dynamic component’s name
```
- But if a number/string after **/product/** in the **url** is matched with the name of a component already existing inside the **product** page, that component with the matched name will get priority over **[productId].js** and be rendered rather than **[productId].js** being rendered.

### Nested dynamic routes

- To implement nested dynamic routes like https://localhost:3000/product/7/review/2, you need a folder structure like **pages/product/[productId]/review/[reviewId].js**. Note that this time **[productId]** is a folder, not a **.js** file. 
    - So, **pages/product/[productId]/review/[reviewId].js** maps to https://localhost:3000/product/7/review/2
- In this mechanism, to achieve the functionality of https://localhost:3000/product/1, (only dynamic, not nested dynamic) you need a folder structure like **pages/product/[productId]/index.js**. You will find **productId** in the **url** dynamically in the **index.js** file.
- Thus you can implement dynamic nested routes by having dynamic segments in the folder name as well as file name.
- Speaking of dynamic multiple path segments, Next JS does offer another feature to handle the same. To know more about the feature, read the next topic. 


### Catch all routes

- This feature applies to scenario where the **url** contains multiple route segments like https://localhost:3000/docs/feature1/concept1
- The folder structure for https://localhost:3000/docs/feature1/concept1 should be **pages/docs/[...params].js** and inside **[...params].js** you can use **useRouter** to get both **feature/** and **concept/** or even more to it like below -

```js
    const router = useRouter();
    const { params = [] } = router.query; 
    // assigned an empty array because initially it is undefined 
    // and may give an error in production
    console.log(params); // [ "features1", "concept1" ]
```
- After getting your dynamic route segments, You can then conditionally render your components or JSX elements like this -

```js
const Doc = () => {
    const router = useRouter();
    const { params = [] } = router.query; 
    // assigned an empty array because initially it is undefined 
    // and may give an error in production
    console.log(params); // [ "features1", "concept1" ]
   
    if (params.length === 2) {
        return (
            <h2>Viewing docs for feature {params[0]} and concept {params[1]}</h2>
        )} else if (params.length === 1) {
        return (
            <h2>Viewing docs for feature {params[0]}</h2>
        )}
    return (
        <div>Docs home page</div>
    )};
   
export default Doc;
```
- But the folder structure **pages/docs/[...params].js** will give a **404** while trying to access https://localhost:3000/docs. To have a quick fix, you can put another pair of square brackets around **[params].js**, so the new folder structure is **pages/docs/[[...params]].js** and https://localhost:3000/docs does not give a **404** and works as expected.

### Link component navigation
You can navigate in the UI using **Link** component offered by Next.js like this -

```js
<Link href="product/2" replace >
     <a>Go to Product 2</a>
</Link>
```

### Navigating programmatically
You can navigate programmatically using **useRouter**.  All other routing variations are valid in this mechanism.

```js
const Home = () => {
    const router = useRouter();
    const handleOrder = () => {
        console.log('Placing the order...');
        router.push('/product');
    };
    return (
        <div>
            <button onClick={handleOrder}>Place order</button>
        </div>
    );
};

```

### Custom 404 page
To provide your custom **404** page, create a **404.js** file in the pages folder.

### Conclusion
So, that is all about routing in NextJS. Hope you liked it. Thanks for reading.