Next.js - Imperitive Routing
Next.js - Programmatic Navigation (Imperative Routing)
Section titled “Next.js - Programmatic Navigation (Imperative Routing)”While the next/link component is the standard way to handle declarative navigation between pages (using <a> tags), Next.js also allows you to navigate programmatically, often referred to as imperative routing.
This is useful when you need to trigger navigation based on user actions (like form submissions), conditional logic, or after asynchronous operations complete.
The primary way to achieve this is by using the useRouter hook.
-
In the Pages Router, import
useRouterfrom'next/router'. It provides methods likerouter.push(),router.replace(),router.back(), etc. -
In the App Router, import
useRouterfrom'next/navigation'. It offers similar methods (push,replace,back,forward,refresh). Note that this hook should only be used in Client Components.
Let’s modify an example page (using the Pages Router context) to demonstrate programmatic navigation with useRouter.
Consider this updated pages/index.js:
import { useRouter } from 'next/router';import Head from 'next/head';
function HomePage(props) { // Get the router object const router = useRouter();
const goToFirstPost = () => { console.log('Navigating to /posts/first-post programmatically...'); router.push('/posts/first-post'); };
const goToPostById = (postId) => { console.log(`Navigating to /posts/${postId}...`); // Example with dynamic route router.push(`/posts/${postId}`); // Or using the object syntax for more options (e.g., query params): // router.push({ // pathname: '/posts/[id]', // query: { id: postId, source: 'button_click' }, // }); };
return ( <> <Head> <title>Welcome to Next.js! (Imperative Routing)</title> </Head> <div> <h1>Welcome to Next.js!</h1> <p>Demonstrating Programmatic Navigation</p>
{/* Button triggering programmatic navigation */} <button onClick={goToFirstPost}> Go to First Post (using router.push) </button>
<br /> <br />
<button onClick={() => goToPostById('my-dynamic-post')}> Go to Dynamic Post (ID: my-dynamic-post) </button>
<br /> <br /> <div> GitHub Stars (from props): {props.stars} </div> </div> </> );}
// Example data fetching (unrelated to routing itself)export async function getServerSideProps(context) { const res = await fetch('https://api.github.com/repos/vercel/next.js'); const json = await res.json(); return { props: { stars: json.stargazers_count || 'N/A' }, };}
export default HomePage;In this example:
- We import
useRouterfrom'next/router'. - Inside the component,
const router = useRouter()gives access to the router instance. - The
goToFirstPostfunction callsrouter.push('/posts/first-post')when the first button is clicked. - The
goToPostByIdfunction demonstrates navigating to a dynamic route (/posts/[id].js) usingrouter.pushwith a template literal or the object syntax.
Running the Development Server
Section titled “Running the Development Server”Start the server:
npm run dev
# Example Output:# ready - started server on 0.0.0.0:3000, url: http://localhost:3000Verify Output
Section titled “Verify Output”-
Open
http://localhost:3000in your browser. -
Click the ‘Go to First Post (using router.push)’ button. You should be navigated to the
/posts/first-postpage, just as if you had clicked a<Link>component. Check your browser’s developer console for the log message. -
Navigate back to the home page.
-
Click the ‘Go to Dynamic Post (ID: my-dynamic-post)’ button. Assuming you have a page setup at
pages/posts/[id].js, you should be navigated to/posts/my-dynamic-post. The dynamic parametermy-dynamic-postwould be available within that page component viarouter.query.id.
router.push() adds the new URL to the browser’s history stack, while router.replace() navigates without adding a new entry, effectively replacing the current URL in the history.