Skip to content

Hooks ​

Hooks offer a way to register callbacks on router lifecycle events.

ts
const route = createRoute({...})
  .onAfterRouteEnter((to, context) => {
    ...
  })

Lifecycle ​

Before Hooks ​

  • onBeforeRouteEnter: Triggered before a route gets mounted.
  • onBeforeRouteUpdate: Triggered before a route changes. Specifically when the route changed but that parent or child didn’t.
  • onBeforeRouteLeave: Triggered before a route is about to be unmounted

After Hooks ​

  • onAfterRouteLeave: Triggered after a route is left.
  • onAfterRouteUpdate: Triggered after a route changes. Specifically when the route changed but that parent or child didn’t.
  • onAfterRouteEnter: Triggered after a route is entered.

On Error ​

  • onError Triggered whenever an unexpected error is thrown. Error hooks are run in the order they were registered. The hook is provided both the error and the error context.

On Rejection ​

  • onRejection Triggered whenever a rejection is triggered. Rejection hooks are run in the order they were registered. The hook is provided both the rejection and the rejection context.

Context ​

The router provides to and a context argument to your hook callback. The context will always include:

PropertyDescription
lifecycle'before' or 'after', depending on the hook's lifecycle.
fromWhat was the route prior to the hook's execution
pushConvenient way to move the user from wherever they were to a new route.
replaceSame as push, but with options: { replace: true }.
rejectTrigger a rejection for the router to handle
signalAn AbortSignal that aborts when the router navigates away from the route.

If the hooks lifecycle is a before hook, you'll also have access to the following property in your context:

PropertyDescription
abortStops the router from continuing with route change

Error Context ​

If the hook is onError, you'll also have access to the following properties in your context:

PropertyDescription
toWhat was the destination route prior to the error being thrown
sourceString value indicating where the error occurred. Possible values are 'props', 'loader', 'hook', and 'component'

Rejection Context ​

If the hook is onRejection, you'll also have access to the following properties in your context:

PropertyDescription
toWhat was the destination route prior to the rejection being triggered
fromWhat was the route prior to the rejection being triggered

Levels ​

Hooks can be registered globally, on your route, or from within a component. This is useful for both providing the most convenient devx, but also can be a useful tool for ensuring proper execution order of your business logic.

Execution Order ​

  1. Global before hooks
  2. Route before hooks
  3. Component before hooks
  4. Component after hooks
  5. Route after hooks
  6. Global after hooks

Global ​

ts
router.onAfterRouteEnter((to, context) => {
  ...
})

Route ​

ts
const route = createRoute({...})
  .onAfterRouteEnter((to, context) => {
    ...
  })

Rejection ​

ts
rejection.onRejection((rejection, context) => {
  ...
})

Component ​

In order to register a hook from within a component, you must use the composition API.

ts
import { onBeforeRouteLeave } from '@kitbag/router'

onBeforeRouteLeave((to, context) => {
  ...
})

WARNING

You cannot register onBeforeRouteEnter or onAfterRouteEnter hooks from within a component, since the component must have been mounted to discover the hook.

Removing Hooks ​

Use remove from the callback context to remove a hook. You can also pass a signal option to remove it when an AbortController aborts. An already-aborted signal skips registration. Component hooks still unregister automatically on unmount.

ts
const controller = new AbortController()

const route = createRoute({...})
  .onAfterRouteEnter((to, { remove }) => {
    console.log(to.href)
    remove()
  }, { signal: controller.signal })

controller.abort()

Global Injection ​

Hooks are run within the context of the Vue app the router is installed. This means you can use vue's inject function to access global values.

ts
import { inject } from 'vue'

router.onAfterRouteEnter(() => {
  const value = inject('global')

  ...
})

Reusable Hooks ​

Use createHook to define a hook once and reuse it with before or after hooks on routes or the router. Hooks can be passed context to enable them to reference other routes and rejections.

ts
import { createHook } from '@kitbag/router'

const logNavigation = createHook({
  hook: (to, { from }) => {
    console.log('Navigation', {
      from: from?.href,
      to: to?.href,
    })
  },
})

Register the created hook on a route or on the router:

ts
import { createRoute, createRouter } from '@kitbag/router'

const account = createRoute({...})
  .onBeforeRouteEnter(logNavigation)

const router = createRouter([account])

router.onAfterRouteEnter(logNavigation)

Hook Lifecycles ​

Use context.lifecycle to distinguish before and after hooks and access abort when it is 'before':

ts
const unsavedChangesHook = createHook({
  hook: (_to, context) => {
    if (context.lifecycle === 'before' && hasUnsavedChanges()) {
      context.abort()
    }
  },
})