Keywords: Next.js | Routing Migration | useRouter
Abstract: This article provides an in-depth exploration of the common error 'NextRouter was not mounted' encountered during migration from the pages directory to the app directory in Next.js 13+ applications. It analyzes the root causes, including changes in import paths for the useRouter hook and significant API adjustments, and offers comprehensive solutions based on usePathname and useSearchParams. Through code examples and comparative analysis, the article helps developers understand the evolution of Next.js routing systems, ensuring smooth transitions in modern architectures.
Problem Background and Error Manifestation
In Next.js 13+ application development, many developers encounter a typical error when migrating from the traditional pages directory structure to the new app directory architecture: NextRouter was not mounted. This error is often accompanied by TypeScript type-checking failures, such as prompts like Argument of type '{ pathname: string; query: { search: string; }; }' is not assignable to parameter of type 'string'. The core issue arises when developers attempt to use the old next/router API for routing operations in new projects based on the app directory, as Next.js 13+ has fundamentally restructured its routing system.
In-Depth Analysis of Error Causes
Next.js 13 introduced the app directory architecture based on React Server Components, leading to significant changes in the routing API. In the traditional pages directory, the useRouter hook is imported from next/router and provides a feature-rich router object supporting methods like pathname, query, and push. However, in the app directory, this API has been simplified and split to better accommodate server component characteristics.
Specifically, the error occurs due to:
- Incorrect Import Path: In the app directory,
useRoutermust be imported fromnext/navigation, notnext/router. The latter is only applicable to the pages directory and will cause improper router initialization in the app directory. - API Interface Changes: The new
useRouterremoves thepathnameandqueryproperties, with these functionalities now provided by separate hooks:usePathnameanduseSearchParams. This reflects Next.js's optimization for modularity and performance. - Type Mismatch: Due to API changes, old code passing object parameters to
router.pushtriggers TypeScript errors, as the new version ofpushonly accepts string parameters.
Solutions and Code Implementation
Based on Next.js official documentation and best practices, here is a complete solution to the NextRouter was not mounted error. First, ensure correct hook imports:
import { useRouter, usePathname, useSearchParams } from "next/navigation";
import { useState } from "react";
Next, refactor the routing logic. Assuming the original code attempts to navigate to a /search page with query parameters in a search function, the new implementation is as follows:
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
const [searchInput, setSearchInput] = useState("");
const search = (e) => {
// Create a new URLSearchParams object to manage query parameters
const params = new URLSearchParams(searchParams.toString());
params.set("search", searchInput);
// Navigate using a string path
router.push(`/search?${params.toString()}`);
};
In this example, usePathname is used to get the current path (if needed), primarily to demonstrate its usage. Key changes include:
router.pushnow only accepts a string parameter, formatted as a combination of path and query string.- Query parameters are managed via the
URLSearchParamsAPI, providing a more standardized way to manipulate URL parameters. - The
useSearchParamshook returns aURLSearchParamsobject for reading current parameters, but modifications require creating a new instance to avoid direct mutation.
Migration Considerations and Best Practices
When migrating from the pages directory to the app directory, developers should note the following key points:
- Hook Import Paths: Always import routing-related hooks from
next/navigation, unless maintaining legacy code in the pages directory. - API Simplification: The new routing system emphasizes simplicity and performance, e.g., removing support for
router.events(in initial Next.js 13 versions), requiring developers to find alternatives for event listening. - Type Safety: Utilize TypeScript to ensure code compatibility and update type definitions promptly to avoid runtime errors.
- Test Environment Configuration: In unit tests, if components use
useRouter, simulate the Next.js context to prevent "NextRouter was not mounted" errors. Use tools like Jest to set up the test environment.
For example, mocking routing in tests:
// In test files
jest.mock("next/navigation", () => ({
useRouter: () => ({
push: jest.fn(),
}),
usePathname: () => "/",
useSearchParams: () => new URLSearchParams(),
}));
Conclusion and Outlook
The NextRouter was not mounted error is a common hurdle during Next.js 13+ migration, but its solution clearly illustrates the framework's evolution direction. By splitting routing functionalities, Next.js enhances code modularity and server-side rendering performance. Developers should actively adapt to these changes, referring to official documentation (e.g., beta.nextjs.org/docs/api-reference/use-router) for the latest information. As Next.js continues to evolve, the routing API is expected to further improve, providing stronger support for building modern web applications.