Skip to content

Commit

Permalink
feat: added descriptive error page + messaging
Browse files Browse the repository at this point in the history
  • Loading branch information
wyattjoh committed Nov 10, 2022
1 parent 6d6d15b commit e2fe144
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 4 deletions.
4 changes: 4 additions & 0 deletions errors/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,10 @@
{
"title": "next-router-not-mounted",
"path": "/errors/next-router-not-mounted.md"
},
{
"title": "navigation-context-missing",
"path": "/errors/navigation-context-missing.md"
}
]
}
Expand Down
34 changes: 34 additions & 0 deletions errors/navigation-context-missing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Missing Navigation Context

#### Why This Error Occurred

This can happen when you have components that are shared between `pages/` and `app/` or were trying to use the `next/navigation` hooks outside the `app/` directory. Situations where you also render components outside a Next.js application (like in unit tests) can also trigger this error.

The following hooks can be affected by missing contexts:

- `useSearchParams()`
- `usePathname()`

When pages are automatically statically optimized (See [Automatic Static Optimization](https://nextjs.org/docs/advanced-features/automatic-static-optimization)) or are rendered as a fallback page (See [Fallback Pages](https://nextjs.org/docs/api-reference/data-fetching/get-static-paths#fallback-pages)) the `useSearchParams()` and `usePathname()` hooks will return `null` until hydration occurs.

> **Note**: These hooks will always return non-null when used in the `app/` directory.
#### Possible Ways to Fix It

If you're migrating components over from `pages/` to `app/`, you can take advantage of the compatibility hooks that are designed to be used in transition when components are shared between `pages/` and `app/`. Instead of writing:

```tsx
import { useRouter, useSearchParams, usePathname } from 'next/navigation'
```

You would write:

```tsx
import { useRouter, useSearchParams, usePathname } from 'next/compat/navigation'
```

When the navigation contexts are not available, they will return `null` instead of throwing an error.

> **Note**: The `useRouter()` hook from `next/compat/navigation` will not return `null` when used in `pages/` as it's been made to be feature compatible with the pages router.
If you're unit testing components that rely on these hooks, you should mock the related hooks from `next/navigation` directly instead.
2 changes: 1 addition & 1 deletion errors/next-router-not-mounted.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#### Why This Error Occurred

A component used `useRouter` outside a Next.js application, or was rendered outside a Next.js application. This can happen when doing unit testing on components that use the `useRouter` hook as they are not configured with Next.js' contexts.
A component used `useRouter` outside a Next.js application, or was rendered outside one. This can happen when doing unit testing on components that use the `useRouter` hook as they are not configured with Next.js' contexts.

#### Possible Ways to Fix It

Expand Down
12 changes: 9 additions & 3 deletions packages/next/client/components/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ export function useSearchParams() {
staticGenerationBailout('useSearchParams')
const searchParams = useContext(SearchParamsContext)
if (!searchParams) {
throw new Error('invariant expected search params context to be mounted')
throw new Error(
'Search Parameters Context was not mounted. See more info here https://nextjs.org/docs/messages/navigation-context-missing'
)
}

const readonlySearchParams = useMemo(() => {
Expand All @@ -39,7 +41,9 @@ export function useSearchParams() {
export function usePathname(): string {
const pathname = useContext(PathnameContext)
if (pathname === null) {
throw new Error('invariant expected pathname context to be mounted')
throw new Error(
'Pathname Context was not mounted. See more info here https://nextjs.org/docs/messages/navigation-context-missing'
)
}

return pathname
Expand Down Expand Up @@ -67,7 +71,9 @@ export {
export function useRouter(): import('../../shared/lib/app-router-context').AppRouterInstance {
const router = useContext(AppRouterContext)
if (router === null) {
throw new Error('invariant expected app router to be mounted')
throw new Error(
'App Router Context was not mounted. See more info here https://nextjs.org/docs/messages/navigation-context-missing'
)
}

return router
Expand Down

0 comments on commit e2fe144

Please sign in to comment.