# Routing

Routing in your components is possible via `@webcomp/router` module.

WebComp router is a modern client side router that provides Express-like route handling, supports history API and hash mode and provides some higher order helpers. Let's go through everything.

## Basic usage

Here's how you can define routes in your component:

```jsx
import { WebComponent } from '@webcomp/core';
import { Router } from '@webcomp/router';

class MyElement extends WebComponent{
  componentDidMount = () => {
    Router.on('/profile/:id', this.handleRouteChange);
  }

  handleRouteChange = (url) => {
    console.log('Route changed! ID:', url.params.id); // "Route changed! ID: 123"
  }

  changeRoute = () => {
    Router.push('/profile/123');
  }

  render() {
    return <button onClick={this.changeRoute}>Change Route</button>
  }
}
```

Your route handler function will receive a `url` object with the following structure:

* **`params`**  - object with url params
* &#x20;**`path`** - Full path string
* &#x20;**`query`** - Parsed object from query string

## Router Methods and Properties

Besides `push` and `on` that we've already seen, router provides a few additional methods and configuration options.

### `Router.mode`

* Default: `hash`

A string indicating router's operation mode. Can be `hash` or `history`. To configure router for a different mode, assign a new value to it:

```javascript
Router.mode = 'history';
```

Keep in mind that this will configure the entire router, so you should only do it once at the **top level** of your app (before you register any of your components).

### `Router.root`

* Default: `/`

A string indicating router's root path. Same as with mode, you can assign a new value to set it:

```javascript
Router.root = '/settings';
```

This should also be configured once at the top level of your app.

### `` `on(route, handlerFunction, persist)` ``

Define a new handler for a route. Optional `persist` argument will prevent a handler from flushing if `Router.flushHandlers` is called.

Calling `Router.on` will return a string ID which you can use to remove handlers later if needed. Usage:

```javascript
Router.on('/profile/:id', (url) => {
  console.log(url.params.id);
})
```

### `removeHandler(id)`

Removes previously defined route handler by it's ID. Usage:

```javascript
Router.removeHandler('_mp6vmcfda');
```

### `flushHandlers()`

Removes all handlers from the router except ones that were defined with `persist` flag.

### `dangerouslyFlushRouter()`

Completely resets router to it's default state. Root is set to `'/'`, mode to `'hash'` and **all** route handlers are removed (even persisted ones).

You will most likely never need to use this method. If you must, use with caution.

### push(path)

Navigate to a new route. Uses \`pushState\` when in \`history\` mode. Usage:

```javascript
Router.push('/path/to/something');
```

### `replace(path)`

Navigate to a new route and replace the history state instead of pushing.\
\&#xNAN;***Note:** Only available in `history` mode.*

## `Routerize` decorator

Defining routes explicitly isn't always convenient. Some times you just want to watch what happens and do stuff based on that. For these use cases, WebComp provides a **`@routerize`** decorator:

```jsx
import { WebComponent } from '@webcomp/core';
import { routerize } from '@webcomp/router';

@routerize
class MyElement extends WebComponent{
  render(props) {
    // props.router.state is the same object that is passed to route handlers
    return <h1>Hello route {props.router.state.path}</h1>
  }
}
```

Here's the structure of `this.props.router` prop that `@routerize` gives you:

```javascript
{
  on(),
  push()
  replace(),
  flushHandlers(),
  dangerouslyFlushRouter(),
  root,
  state: {
    path,
    params: {},
    query: {},
  },
}
```

This will be updated on every route change, so you can rely on the prop directly, without needing to specify route handlers.

***Note:** Due to how router works by default, your component will be re-rendered on mount when routerized. It's usually not a big deal, but if it is, you should use  a custom router (see below) with a `skipInitial` option.*

## \<Route /> Component

If you only need to watch routes to change your rendered content, you can use `<Route />` component to do that:

```jsx
import { WebComponent } from '@webcomp/core';
import { Route } from '@webcomp/router';

class MyElement extends WebComponent{
  render(props) {
    return (
      <div>
        <Route path="/">
          <h1>Home Page</h1>
        </Route>
        <Route path="/settings">
          <h1>Settings</h1>
        </Route>
      </div>
    )
  }
}
```

### Shallow routes

Besides child node, `Route` also supports passing a \`component\` prop for render. If you do this, rendered component will automatically be routerized. You can bypass this behavior by using **`shallow`** prop.

```jsx
import { WebComponent } from '@webcomp/core';
import { Route } from '@webcomp/router';
import FancyHeader from './FancyHeader';

class MyElement extends WebComponent{
  render(props) {
    return (
      <div>
        <Route path="/" component={FancyHeader} />
        <Route path="/settings" component={FancyHeader} shallow />
      </div>
    )
  }
}
```

In the above example, `FancyHeader` component on route `/` will get `this.props.router`, but the one on `/settings` route won't.

## Advanced Usage

### Custom Routers

In some cases you need to have different router configurations for different components. WebComp allows you to create custom routers for this.

Default `Router` is an instance of a `WCRouter` class, which you can reuse or extend.

```javascript
import { WCRouter } from '@webcomp/router';

class SafeRouter extends WCRouter {
  constructor(options) {
    super(options);

    this.dangerouslyFlushRouter = () => throw new Error("Safe router doesn't allow flushing");
    this.flushHandlers = () => throw new Error("Safe router doesn't allow flushing");
  }
}

const MyCustomRouter = new SafeRouter({ skipInitial: true, mode: 'history' });
```

### Custom router options

* **`skipInitial`** - If this is set, router won't fire handlers on initial page load.
* **`mode`** - Set default mode. Can be `'hash'` or `'history'`.
* **`root`** - Set custom default root

### Routerizing with custom router

The `@routerize` decorator uses default router instance. If you want to routerize your component with your custom router, you can use **`routerizeWith`** decorator instead:

```javascript
import { WebComponent } from '@webcomp/core';
import { WCRouter, routerizeWith } from '@webcomp/router';

const CustomRouter = new WCRouter({ skipInitial: true });

@routerizeWith(CustomRouter)
class MyElement extends WebComponent{
  render(props) {
    return <h1>...</h1>
  }
}
```

### Using custom routers with `<Route />`

You can also use custom routers with `<Route />` component by providing it as a **`customRouter`** prop:

```jsx
import { WebComponent } from '@webcomp/core';
import { WCRouter, Route } from '@webcomp/router';
import FancyHeader from './FancyHeader';

const MyRouter = new WCRouter({ skipInitial: true });

class MyElement extends WebComponent{
  render(props) {
    return (
      <div>
        <Route path="/" component={FancyHeader} customRouter={MyRouter} />
      </div>
    )
  }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://webcomp.gitbook.io/webcomp/routing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
