Hooks
Hooks offer a way to register callbacks on router lifecycle events.
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:
| Property | Description |
|---|---|
| lifecycle | 'before' or 'after', depending on the hook's lifecycle. |
| from | What was the route prior to the hook's execution |
| push | Convenient way to move the user from wherever they were to a new route. |
| replace | Same as push, but with options: { replace: true }. |
| reject | Trigger a rejection for the router to handle |
| signal | An 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:
| Property | Description |
|---|---|
| abort | Stops 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:
| Property | Description |
|---|---|
| to | What was the destination route prior to the error being thrown |
| source | String 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:
| Property | Description |
|---|---|
| to | What was the destination route prior to the rejection being triggered |
| from | What 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
- Global before hooks
- Route before hooks
- Component before hooks
- Component after hooks
- Route after hooks
- Global after hooks
Global
router.onAfterRouteEnter((to, context) => {
...
})Route
const route = createRoute({...})
.onAfterRouteEnter((to, context) => {
...
})Rejection
rejection.onRejection((rejection, context) => {
...
})Component
In order to register a hook from within a component, you must use the composition API.
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.
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.
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.
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:
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':
const unsavedChangesHook = createHook({
hook: (_to, context) => {
if (context.lifecycle === 'before' && hasUnsavedChanges()) {
context.abort()
}
},
})