Skip to content

Make useBlocker exception on unknown routes optional #4965

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

sescandell
Copy link

@sescandell sescandell commented Aug 16, 2025

Adds a throwOnUnknownRoute option to the useBlocker hook for both React and Solid.

When set to false, this option prevents useBlocker from throwing an exception if the user navigates to a route that is not recognized by the router. Instead, the navigation is allowed to proceed. This is useful for applications that are progressively adopting the router and may have links that navigate from router-managed pages to non-router-managed pages.

The default value is true to maintain the existing behavior.

I'm not sure the option is really necessary. We could imagine to completely reconsider throwing an exception from this function (I don't see anyway how the user could catch it. Let me know if we already can).

Summary by CodeRabbit

  • New Features

    • Added throwOnUnknownRoute option to useBlocker (React & Solid); default preserves previous strict behavior.
    • Blocker callbacks (current/next) may be undefined to represent unresolved locations.
    • Exposed Link and Outlet in public APIs (React & Solid).
  • Bug Fixes

    • Guarded against undefined current/next in blocking logic to prevent runtime crashes.
  • Tests

    • Added tests for unknown-route navigation with throwOnUnknownRoute:false and refined type assertions.
  • Documentation

    • Updated useBlocker docs and examples to handle optional current/next.

Copy link

coderabbitai bot commented Aug 16, 2025

Walkthrough

Adds UseBlockerOpts.throwOnUnknownRoute?: boolean (runtime default true), makes blocker current/next locations possibly undefined, changes location parsing to return undefined for unknown routes, conditionally throws when the flag is true, updates effect deps, adjusts types, tests, and public exports (Link, Outlet).

Changes

Cohort / File(s) Summary of changes
React useBlocker source
packages/react-router/src/useBlocker.tsx
Added UseBlockerOpts.throwOnUnknownRoute?: boolean (runtime default true). getLocation may return `AnyShouldBlockFnLocation
Solid useBlocker source
packages/solid-router/src/useBlocker.tsx
Same changes as React: new throwOnUnknownRoute (default true), getLocation may return undefined, current/next optional in public types, conditional throws, effect deps updated.
React type tests
packages/react-router/tests/useBlocker.test-d.tsx
Type assertions refined: .exclude(undefined) chained on inferred current/next types for shouldBlockFn parameters.
Solid type tests
packages/solid-router/tests/useBlocker.test-d.tsx
Same type-assertion refinements: .exclude(undefined) for current/next.
React runtime tests
packages/react-router/tests/useBlocker.test.tsx
Added test for throwOnUnknownRoute: false navigating to unknown route; guarded next with optional chaining (next?.fullPath); import formatting changed; tests use exported Link and Outlet.
Solid runtime tests
packages/solid-router/tests/useBlocker.test.tsx
Added test for throwOnUnknownRoute: false; guarded next with optional chaining; tests use exported Link and Outlet.
Public exports
packages/react-router/src/*, packages/solid-router/src/*
Link and Outlet added to public exports (used by tests and consumers).

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant Router
  participant useBlocker
  participant Parser as parseLocation
  participant Guard as throwOnUnknownRoute?

  App->>Router: navigate(to)
  Router->>useBlocker: run blocker check
  useBlocker->>Parser: parse current location
  Parser-->>useBlocker: current | undefined
  useBlocker->>Parser: parse next location
  Parser-->>useBlocker: next | undefined
  useBlocker->>Guard: is throwOnUnknownRoute true?
  alt throwOnUnknownRoute && (current or next is undefined)
    useBlocker-->>Router: throw Error("No route found for location <href>")
    Router-->>App: error
  else
    useBlocker-->>Router: call shouldBlockFn({ current?, next? })
    Router-->>App: proceed or block navigation
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I nibble at maps both known and new,
Sometimes a path is missing too.
A toggle in paw—strict or free,
I guard the gate or let you be.
Hop on, Link and Outlet, follow me. 🐇

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (7)
packages/solid-router/tests/useBlocker.test.tsx (1)

498-543: Unknown-route test covers the new flag; minor consistency and assertion nitpicks

The test effectively exercises throwOnUnknownRoute: false and validates the Not Found path. Two small improvements:

  • Use the same event helper throughout the file for consistency.
  • Optionally assert the URL change to '/unknown' to tighten the expectation.

Apply this diff to use fireEvent and add an optional pathname assertion:

-    const unknownLink = screen.getByTestId('unknown-link')
-    unknownLink.click()
+    const unknownLink = screen.getByTestId('unknown-link')
+    fireEvent.click(unknownLink)
@@
-    expect(notFoundComponent).toBeInTheDocument()
+    expect(notFoundComponent).toBeInTheDocument()
+    // Optional: also assert the URL changed to the unknown path
+    expect(window.location.pathname).toBe('/unknown')

Question: do we still need await router.load() here? The rest of the tests don’t call it. If not required for this scenario, removing it could shave a bit of test time.

packages/solid-router/src/useBlocker.tsx (2)

45-47: Making current/next optional in public shapes is sensible; ensure docs callout

Allowing current and next to be undefined in BlockerResolver and ShouldBlockFnArgs matches the runtime behavior when navigating to unknown routes. This is a widening change and source-compatible, but it does introduce potential undefined at runtime for consumers who didn’t guard previously. Please add a brief note in the API docs/CHANGELOG so users know to guard or use optional chaining.

Also applies to: 61-63


207-219: Guarded throws on unknown current/next are correct; consider DRYing the duplication

Both current and next unknown are handled with near-identical throw logic. Not a big deal, but a tiny helper would reduce duplication and keep messages consistent.

Example refactor within blockerFnComposed:

-      const current = getLocation(blockerFnArgs.currentLocation)
-      if (!current && props.throwOnUnknownRoute) {
-        throw new Error(
-          `No route found for location ${blockerFnArgs.currentLocation.href}`,
-        )
-      }
+      const current = getLocation(blockerFnArgs.currentLocation)
+      const ensureKnown = (loc: any, historyLoc: HistoryLocation, label: 'current' | 'next') => {
+        if (!loc && props.throwOnUnknownRoute) {
+          throw new Error(`No route found for ${label} location ${historyLoc.href}`)
+        }
+      }
+      ensureKnown(current, blockerFnArgs.currentLocation, 'current')
 
       const next = getLocation(blockerFnArgs.nextLocation)
-      if (!next && props.throwOnUnknownRoute) {
-        throw new Error(
-          `No route found for location ${blockerFnArgs.nextLocation.href}`,
-        )
-      }
+      ensureKnown(next, blockerFnArgs.nextLocation, 'next')
packages/solid-router/tests/useBlocker.test-d.tsx (1)

68-68: Typo: “corrent” → “correct” in test title

Small spelling fix to improve readability in test descriptions.

-test('shouldBlockFn has corrent action', () => {
+test('shouldBlockFn has correct action', () => {
packages/react-router/src/useBlocker.tsx (2)

76-77: New option throwOnUnknownRoute with default true—LGTM; consider documenting inline

The default preserves existing behavior. Consider adding a short JSDoc on the option for clarity in editors/IDE.

Proposed inline doc:

 export type UseBlockerOpts<
   TRouter extends AnyRouter = RegisteredRouter,
   TWithResolver extends boolean = boolean,
 > = {
   shouldBlockFn: ShouldBlockFn<TRouter>
   enableBeforeUnload?: boolean | (() => boolean)
   disabled?: boolean
   withResolver?: TWithResolver
-  throwOnUnknownRoute?: boolean
+  /**
+   * When true (default), navigating to a location that does not match any route
+   * will throw an error from the blocker. Set to false to allow such navigation
+   * (useful during progressive adoption or when linking to non-router pages).
+   */
+  throwOnUnknownRoute?: boolean
 }

Also applies to: 161-162


199-203: Unknown-route error throws: minor messaging/DRY nit

Throwing only when throwOnUnknownRoute is true is correct. Two small nits:

  • Error message could include pathname and search for readability in tests/logs.
  • The two throw branches are duplicated; a tiny helper (e.g., assertKnownRoute) would reduce repetition.

No functional change required.

Also applies to: 205-209

packages/react-router/tests/useBlocker.test.tsx (1)

451-497: Use RTL’s fireEvent.click for consistency

– Replace the direct .click() call with fireEvent.click
– Add a complementary test to verify that the default throwOnUnknownRoute=true still throws on navigation to an unknown path

Suggested diff:

-    const unknownLink = screen.getByTestId('unknown-link')
-    unknownLink.click()
+    const unknownLink = screen.getByTestId('unknown-link')
+    fireEvent.click(unknownLink)

Consider adding, for example:

test('throws when navigating to an unknown route by default', async () => {
  // setup routes without throwOnUnknownRoute override…
  expect(() => {
    fireEvent.click(screen.getByTestId('unknown-link'))
  }).toThrow(/No route found for location/)
})

[optional_refactors_recommended]

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1ccf7c8 and 9e08563.

📒 Files selected for processing (6)
  • packages/react-router/src/useBlocker.tsx (7 hunks)
  • packages/react-router/tests/useBlocker.test-d.tsx (2 hunks)
  • packages/react-router/tests/useBlocker.test.tsx (3 hunks)
  • packages/solid-router/src/useBlocker.tsx (6 hunks)
  • packages/solid-router/tests/useBlocker.test-d.tsx (2 hunks)
  • packages/solid-router/tests/useBlocker.test.tsx (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
packages/solid-router/tests/useBlocker.test.tsx (1)
packages/solid-router/src/useBlocker.tsx (1)
  • useBlocker (160-269)
packages/react-router/src/useBlocker.tsx (1)
packages/history/src/index.ts (1)
  • location (162-164)
🔇 Additional comments (13)
packages/solid-router/tests/useBlocker.test.tsx (2)

9-10: Public API import of Link and Outlet looks correct

Good to see these exported through ../src and exercised in tests; this validates consumer-facing availability.


350-351: Optional chaining on next is appropriate with the new API

Guarding with next?.fullPath aligns with current/next potentially being undefined.

packages/solid-router/src/useBlocker.tsx (3)

77-78: New option throwOnUnknownRoute on UseBlockerOpts is well-placed

The option belongs here and lines up with the new behavior. No issues.


169-171: Default throwOnUnknownRoute: true preserves existing behavior

Merging defaults with Solid.mergeProps keeps prior semantics unless explicitly opted out. Good backward compatibility stance.


189-197: Returning undefined for getLocation on unknown routes is the right pivot

Deferring the decision to throw to the flag instead of within getLocation simplifies reuse and testing.

packages/solid-router/tests/useBlocker.test-d.tsx (1)

109-111: Type expectations updated to reflect optional current/next

Using .exclude(undefined) before narrowing to routeId types matches the widened ShouldBlockFnArgs. Looks good.

Also applies to: 118-120

packages/react-router/src/useBlocker.tsx (3)

44-46: Making current/next optional matches runtime semantics—LGTM

Allowing current/next to be undefined in both the resolver and shouldBlockFn args aligns with the new unknown-route behavior and avoids unsafe assumptions. Type tests reflect this correctly.

Also applies to: 59-62


178-181: getLocation returning undefined on unmatched routes—LGTM

This cleanly distinguishes known vs. unknown routes without throwing, deferring the decision to the throwOnUnknownRoute guard and consumer code.

Also applies to: 186-196


258-259: Including throwOnUnknownRoute in effect deps—LGTM

Ensures the blocker is rebound if this flag toggles at runtime.

packages/react-router/tests/useBlocker.test-d.tsx (1)

112-113: Type narrowing with .exclude(undefined) is correct

These assertions reflect the updated API where current/next can be undefined. Solid type-level coverage.

Also applies to: 121-122

packages/react-router/tests/useBlocker.test.tsx (3)

4-9: Import reshuffle—LGTM

No functional impact; consistent with RTL usage patterns.


13-15: Public exports Link/Outlet use in tests—LGTM

Good exercise of the public surface and aligns with the new unknown-route test setup.


369-371: Optional chaining on next.fullPath avoids undefined access—LGTM

Matches the new useBlocker typing where next can be undefined.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (5)
packages/react-router/src/useBlocker.tsx (5)

44-46: Type surface widened: BlockerResolver.current/next can be undefined

This is a breaking type change for consumers using the resolver (e.g., UI code reading resolver.next.fullPath now needs guards). If the intended runtime behavior with throwOnUnknownRoute=false is to “allow navigation to proceed,” consider short-circuiting before exposing a blocked resolver with undefined locations. That would let you keep the resolver’s blocked shape non-undefined and avoid the breaking type change.

If you choose that path, add an early return (see separate comment with diff) and you could revert the type widening here.


60-62: Widening ShouldBlockFnArgs to include undefined may break existing shouldBlockFn implementations

Existing user-provided shouldBlockFn that assume non-undefined current/next will now need null checks. If you want to preserve backward compatibility and the “proceed” semantics for unknown routes, consider early-returning false (don’t block) when either location is unknown and keep ShouldBlockFnArgs non-undefined. Otherwise, please document this new possibility prominently.

Can you confirm that docs/examples and migration notes are updated to reflect that current/next can now be undefined in shouldBlockFn?


199-204: Clarify error message context (say “current” and suggest the option)

Differentiate between current vs next to aid debugging and hint at the new option. Example tweak:

-        throw new Error(
-          `No route found for location ${blockerFnArgs.currentLocation.href}`,
-        )
+        throw new Error(
+          `useBlocker: No route found for current location ${blockerFnArgs.currentLocation.href}. ` +
+          `Set throwOnUnknownRoute: false to allow navigation to proceed.`
+        )

205-209: Clarify error message for “next” location as well

Mirror the “current” message for next:

-        throw new Error(
-          `No route found for location ${blockerFnArgs.nextLocation.href}`,
-        )
+        throw new Error(
+          `useBlocker: No route found for next location ${blockerFnArgs.nextLocation.href}. ` +
+          `Set throwOnUnknownRoute: false to allow navigation to proceed.`
+        )

210-216: Optional: Short-circuit instead of calling shouldBlockFn with undefined

If the intent of throwOnUnknownRoute=false is to “let navigation proceed” for unknown routes, you can avoid invoking shouldBlockFn with undefined and prevent exposing a blocked resolver with undefined locations. This also reduces the type surface change pressure.

       const next = getLocation(blockerFnArgs.nextLocation)
       if (!next && throwOnUnknownRoute) {
         throw new Error(
           `No route found for location ${blockerFnArgs.nextLocation.href}`,
         )
       }
 
+      // Optional: allow unknown routes to proceed without invoking shouldBlockFn
+      // This preserves previous ShouldBlockFnArgs shape and avoids blocking with undefined locations.
+      if (!current || !next) {
+        return false
+      }
+
       const shouldBlock = await shouldBlockFn({
         action: blockerFnArgs.action,
         current,
         next,
       })
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9e08563 and 36dcae1.

📒 Files selected for processing (2)
  • packages/react-router/src/useBlocker.tsx (7 hunks)
  • packages/solid-router/src/useBlocker.tsx (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/solid-router/src/useBlocker.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/react-router/src/useBlocker.tsx (1)
packages/history/src/index.ts (1)
  • location (162-164)
🔇 Additional comments (4)
packages/react-router/src/useBlocker.tsx (4)

76-77: New option throwOnUnknownRoute is clear and keeps default behavior intact

Option looks good and the default true preserves existing behavior. Nice addition for progressive adoption scenarios.


161-162: Default assignment preserves current behavior

Destructuring with throwOnUnknownRoute = true maintains the existing runtime default for all call sites (including legacy ones). LGTM.


187-187: Returning undefined for unmatched routes aligns with the new option

This is the correct pivot to enable the configurable behavior and lines up with the test intent described in the PR.


258-259: Including throwOnUnknownRoute in useEffect deps is correct

Ensures the blocker re-registers when the option changes. LGTM.

Comment on lines 180 to 181
): AnyShouldBlockFnLocation|undefined {
const parsedLocation = router.parseLocation(location)
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Confirm parseLocation signature change (1 arg vs 2 args)

This switches to router.parseLocation(location). If parseLocation previously accepted two params (e.g., parseLocation(undefined, location)), please verify the current signature across router-core so we don’t silently break on older versions or alternate adapters.


🏁 Script executed:

#!/bin/bash
# Verify parseLocation signature(s) across the repo
# 1) Look for parseLocation declarations (function or const)
rg -nP -C2 '(function|const)\s+parseLocation\s*\(' --type=ts --no-ignore-vcs
# 2) Inspect all call sites for argument count
rg -nP -C2 'parseLocation\s*\(' --type=ts --no-ignore-vcs

Length of output: 2920


🏁 Script executed:

#!/bin/bash
echo "=== Router-core parseLocation definition context ==="
rg -nP "parseLocation" -C5 packages/router-core/src/router.ts

echo
echo "=== History parseLocation definition context ==="
rg -nP "function parseLocation" -C5 packages/history/src/index.ts

Length of output: 1465


Fix parseLocation usage in useBlocker

The call

const parsedLocation = router.parseLocation(location)

passes your location as the first parameter (previousLocation), leaving the actual target (locationToParse) undefined. In router-core, parseLocation is still defined as

parseLocation: ParseLocationFn<TRouteTree> = (
  previousLocation,
  locationToParse,
) => {  }

so you must supply both arguments.

• packages/react-router/src/useBlocker.tsx (around line 181)
– Change
const parsedLocation = router.parseLocation(location)
– To
const parsedLocation = router.parseLocation(undefined, location)

🤖 Prompt for AI Agents
In packages/react-router/src/useBlocker.tsx around lines 180 to 181, the call to
router.parseLocation passes the target location as the first parameter
(previousLocation) leaving the second parameter undefined; change the call to
pass undefined as the previousLocation and the current location as the second
argument (i.e., call parseLocation(undefined, location)) so both parameters
expected by ParseLocationFn are provided.

@github-actions github-actions bot added the documentation Everything documentation related label Aug 16, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
docs/router/framework/react/api/router/useBlockerHook.md (1)

31-35: Clarify when current/next can be undefined relative to throwOnUnknownRoute.

Great to see the types reflect the new behavior. Add a short note right after the type block to explain that with the default (throwOnUnknownRoute: true), these will be defined, and they’re only possibly undefined when the option is set to false. This removes ambiguity for readers.

Apply this diff:

 type ShouldBlockFnArgs = {
   current: ShouldBlockFnLocation | undefined
   next: ShouldBlockFnLocation | undefined
   action: HistoryAction
 }

+Note: When throwOnUnknownRoute is true (default), current and next are guaranteed to be defined. Set throwOnUnknownRoute to false to allow unknown routes, in which case either may be undefined.


</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

**💡 Knowledge Base configuration:**

- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between c14c387cb12a55b3fb8835f393128ea29e3a4a60 and 2ac23a7e6f144c595d467143c0de668cf503a342.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `docs/router/framework/react/api/router/useBlockerHook.md` (6 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 LanguageTool</summary>

<details>
<summary>docs/router/framework/react/api/router/useBlockerHook.md</summary>

[grammar] ~58-~58: There might be a mistake here.
Context: ...Route` option  - Optional - defaults to `true` - Type: `boolean` - Specify if the hook sh...

(QB_NEW_EN)

---

[grammar] ~59-~59: There might be a mistake here.
Context: ...- Optional - defaults to `true` - Type: `boolean` - Specify if the hook should throw an exce...

(QB_NEW_EN)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (2)</summary><blockquote>

<details>
<summary>docs/router/framework/react/api/router/useBlockerHook.md (2)</summary>

`129-129`: **LGTM: safe fallback for unknown destinations.**

Using `next?.pathname ?? 'Unknown Path'` is concise and prevents runtime errors when the next location is unavailable.

---

`204-207`: **LGTM: safe optional access in type-narrowing example.**

Using `current?`/`next?` here is consistent with the new types and avoids crashes when unknown routes are allowed.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment on lines +56 to +61
### `options.throwOnUnknownRoute` option

- Optional - defaults to `true`
- Type: `boolean`
- Specify if the hook should throw an exception when either the current or next locations is unkown

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix typo and grammar in the throwOnUnknownRoute option description.

“locations is unkown” → “location cannot be resolved” (and singular agreement). This is user-facing; fix it.

-### `options.throwOnUnknownRoute` option
-
-- Optional - defaults to `true`
-- Type: `boolean`
-- Specify if the hook should throw an exception when either the current or next locations is unkown
+### `options.throwOnUnknownRoute` option
+
+- Optional - defaults to `true`
+- Type: `boolean`
+- Specify whether the hook should throw when either the current or next location cannot be resolved.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### `options.throwOnUnknownRoute` option
- Optional - defaults to `true`
- Type: `boolean`
- Specify if the hook should throw an exception when either the current or next locations is unkown
### `options.throwOnUnknownRoute` option
- Optional - defaults to `true`
- Type: `boolean`
- Specify whether the hook should throw when either the current or next location cannot be resolved.
🧰 Tools
🪛 LanguageTool

[grammar] ~58-~58: There might be a mistake here.
Context: ...Routeoption - Optional - defaults totrue- Type:boolean` - Specify if the hook sh...

(QB_NEW_EN)


[grammar] ~59-~59: There might be a mistake here.
Context: ...- Optional - defaults to true - Type: boolean - Specify if the hook should throw an exce...

(QB_NEW_EN)

🤖 Prompt for AI Agents
In docs/router/framework/react/api/router/useBlockerHook.md around lines 56 to
61, the description for the `options.throwOnUnknownRoute` option contains a typo
and grammatical error; update the bullet text so it reads: "Specify if the hook
should throw an exception when either the current or next location cannot be
resolved" (use singular "location" and the phrase "cannot be resolved" instead
of "is unkown").

Comment on lines 146 to 148
shouldBlockFn: ({ next }) => {
return !next.pathname.includes('step/')
return next && !next.pathname.includes('step/')
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Return type bug: expression can return undefined, not boolean.

return next && ... yields undefined when next is undefined, violating the documented contract that shouldBlockFn returns a boolean. Use a ternary or double negation.

-      return next && !next.pathname.includes('step/')
+      // If `next` is unknown, do not block
+      return next ? !next.pathname.includes('step/') : false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
shouldBlockFn: ({ next }) => {
return !next.pathname.includes('step/')
return next && !next.pathname.includes('step/')
},
shouldBlockFn: ({ next }) => {
// If `next` is unknown, do not block
return next ? !next.pathname.includes('step/') : false
},
🤖 Prompt for AI Agents
In docs/router/framework/react/api/router/useBlockerHook.md around lines 146 to
148, the shouldBlockFn uses "return next && !next.pathname.includes('step/')"
which can return undefined when next is undefined; change it to return an
explicit boolean such as "next ? !next.pathname.includes('step/')" or use
double-negation "!!next && !next.pathname.includes('step/')" so the function
always returns a boolean.

@@ -170,7 +176,7 @@ function MyComponent() {

useBlocker({
shouldBlockFn: ({ next }) => {
if (next.pathname.includes('step/')) {
if (next?.pathname.includes('step/')) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Optional chaining is incomplete; potential runtime error.

next?.pathname.includes(...) will still call .includes on undefined when pathname is missing. Chain ?. on pathname as well.

-      if (next?.pathname.includes('step/')) {
+      if (next?.pathname?.includes('step/')) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (next?.pathname.includes('step/')) {
if (next?.pathname?.includes('step/')) {
🤖 Prompt for AI Agents
In docs/router/framework/react/api/router/useBlockerHook.md around line 179, the
expression next?.pathname.includes('step/') can throw if pathname is undefined;
change it to use optional chaining on pathname as well
(next?.pathname?.includes('step/')) so .includes is only called when pathname
exists.

@schiller-manuel
Copy link
Contributor

thanks for this PR.
we are in a feature freeze right now until the next start alpha is merged to main.
we will then revisit this PR, so please be a bit patient

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

Successfully merging this pull request may close these issues.

2 participants