Skip to content
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

next/compat/navigation hooks #42605

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions errors/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,10 @@
"title": "context-in-server-component",
"path": "/errors/context-in-server-component.md"
},
{
"title": "navigation-context-missing",
"path": "/errors/navigation-context-missing.md"
},
{
"title": "react-client-hook-in-server-component",
"path": "/errors/react-client-hook-in-server-component.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 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.
timneutkens marked this conversation as resolved.
Show resolved Hide resolved

> **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.
23 changes: 19 additions & 4 deletions errors/next-router-not-mounted.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
# NextRouter was not mounted
# `NextRouter` was not mounted

#### 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 that used `useRouter` was rendered outside the `pages/` directory. This can happen when migrating to the `app/` directory. Situations where you also render components outside a Next.js application (like in unit tests) can also trigger this error.

#### Possible Ways to Fix It

If used in a test, mock out the router by mocking the `next/router`'s `useRouter()` hook.
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 } from 'next/router'
```

You would write:

```tsx
import { useRouter } from 'next/compat/router'
```

When the router context is not available, this hook will return `null` instead of throwing an error. Developers should migrate over to the new router hook available at `next/navigation` which is fully supported in `app/`.

If you're unit testing components that rely on these hooks, you should mock the the `next/router`'s `useRouter()` hook instead.

### Useful Links

- [next-router-mock](https://www.npmjs.com/package/next-router-mock)
- [`next-router-mock`](https://www.npmjs.com/package/next-router-mock)
- [`useRouter` from `next/navigation`](https://beta.nextjs.org/docs/api-reference/use-router)
1 change: 1 addition & 0 deletions packages/next/compat/navigation.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../dist/client/compat/navigation'
1 change: 1 addition & 0 deletions packages/next/compat/navigation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('../dist/client/compat/navigation')
1 change: 1 addition & 0 deletions packages/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"config.js",
"config.d.ts",
"constants.js",
"compat",
"constants.d.ts",
"document.js",
"document.d.ts",
Expand Down
Loading