Skip to content

Conversation

@tuncayuk
Copy link
Contributor

@tuncayuk tuncayuk commented Dec 2, 2025

Summary

Adds a new afterEach hook to the router that executes after navigation completes, providing access to both the route objects and their corresponding component instances.

Changes

  • Added afterEach and after hook execution in the navigate function
  • The hook is called after the new view is set as the active view but before focus is transferred
  • Hook receives an object with:
    • to: The destination route
    • toComponent: The destination component instance
    • from: The previous route (or undefined if navigating to the first route)
    • fromComponent: The previous component instance (or null if reusing or no previous view)

@github-actions
Copy link

github-actions bot commented Dec 2, 2025

Test Results: ✅ PASSED

Run at: 2025-12-02T12:32:50.640Z

Summary:
passed: 917 failed: 0 of 917 tests

@github-actions
Copy link

github-actions bot commented Dec 4, 2025

Test Results: ✅ PASSED

Run at: 2025-12-04T11:52:20.264Z

Summary:
passed: 917 failed: 0 of 917 tests

@github-actions
Copy link

github-actions bot commented Dec 4, 2025

Test Results: ✅ PASSED

Run at: 2025-12-04T14:02:35.159Z

Summary:
passed: 917 failed: 0 of 917 tests

@github-actions
Copy link

Test Results: ✅ PASSED

Run at: 2025-12-18T14:14:47.719Z

Summary:
passed: 917 failed: 0 of 917 tests

@github-actions
Copy link

Test Results: ✅ PASSED

Run at: 2025-12-18T14:23:07.765Z

Summary:
passed: 917 failed: 0 of 917 tests

@tuncayuk tuncayuk requested a review from il-sairamg December 18, 2025 14:23
}

if (this.parent[symbols.routerHooks]) {
const hooks = this.parent[symbols.routerHooks]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removeView() isn’t awaited, so “after” hooks can run while the exit transition / cleanup is still in progress. Consider awaiting cleanup.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed removeView() to await.

if (hooks.afterEach) {
try {
// Get the previous view before it's removed
const previousView =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

previousView is derived from children after mutation, which can be fragile and may resolve to the root container. Capturing the removed oldView would be more reliable. Same applies to the route.hooks.after block below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used oldView instead of previousView. Thanks.

index.d.ts Outdated
export interface RouterHooks {
init?: () => Promise<> | void;
beforeEach?: (to: Route, from: Route) => string | Route | Promise<string | Route> | void;
afterEach?: (to: Route, toComponent: ComponentBase, from: Route, fromComponent: ComponentBase) => string | Route | Promise<string | Route> | void;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typing: from / fromComponent can be undefined / null at runtime (first nav, reuse). Consider changing both afterEach and after to from?: Route and fromComponent: ComponentBase | null (or guarantee non-null in implementation).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type definition changed as requested. Thanks!

@github-actions
Copy link

Test Results: ✅ PASSED

Run at: 2025-12-19T17:42:51.845Z

Summary:
passed: 917 failed: 0 of 917 tests

@github-actions
Copy link

Test Results: ✅ PASSED

Run at: 2025-12-19T17:48:01.742Z

Summary:
passed: 917 failed: 0 of 917 tests

@github-actions
Copy link

Test Results: ✅ PASSED

Run at: 2025-12-19T17:52:25.069Z

Summary:
passed: 917 failed: 0 of 917 tests

@tuncayuk tuncayuk requested a review from il-sairamg December 19, 2025 17:52
}

export interface RouterHooks {
init?: () => Promise<> | void;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Promise<> is invalid TypeScript syntax; use Promise instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

await setOrAnimate(holder, route.transition.in, shouldAnimate)
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 498: route.transition.length is undefined because route.transition is an object.
Using transition.in.length - 1 ensures the last in-transition is awaited.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


export interface RouteHooks {
before?: (to: Route, from: Route) => string | Route | Promise<string | Route>;
after?: (to: Route, toComponent: ComponentBase, from: Route | undefined, fromComponent: ComponentBase | null) => string | Route | Promise<string | Route>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the signature of the after hook not the same as the before hook, with just to and from? That would make more sense to me and make the API more predictable

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My goal is to use the after navigation hook to trigger shared, post-navigation API calls from the destination component (toComponent).

For example, if a component implements an analytics API like sendAnalytics(), we can automatically call it after the route change completes—so each page can own its own analytics logic, while the hook handles the common wiring.

Example:

after(to, toComponent, from, fromComponent) {
  // Send analytics after navigating to the new page,
  // but only if the destination component exposes `sendAnalytics`.
  toComponent?.sendAnalytics?.();
}

If you want I can remove new params.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants