Home

Resetting State on Next.js Route Change

Component state doesn't change when navigating between dynamic routes in Next.js that use the same component. useEffect can help.

One of Next.js's most powerful features, dynamic routes, can be challenging when it comes to managing the state of components that are used on multiple pages.

Consider a dynamic route (pages/[[...slug]].js) that tells Next we have two routes for that page: / and /other-page.

pages/[[...slug]].js

export default function DynamicPage(props) {
return (
<div style={{ margin: "2rem" }}>
<h1>{props.title}</h1>
</div>
);
}

export async function getStaticProps(context) {
const title = context.params?.slug ? "Page 2" : "Page 1";
return { props: { title } };
}

export async function getStaticPaths() {
return {
paths: ["/", "/other-page"],
fallback: false,
};
}

On both pages we're going to load a button component that has a count clicker, along with a header that uses next/router to help us quickly navigate between pages without performing a full reload.

pages/[[...slug]].js

import { Button } from "../components/Button.jsx";
import { Header } from "../components/Header.jsx";

export default function DynamicPage(props) {
return (
<div style={{ margin: "2rem" }}>
<Header />
<h1>{props.title}</h1>
<Button />
</div>
);
}

// ...

The header looks like this:

comopnents/Header.jsx

import Link from "next/link";

export const Header = () => {
return (
<nav>
<Link href="/">
<a style={{ marginRight: "0.5rem" }}>Page 1</a>
</Link>
<Link href="/other-page">Page 2</Link>
</nav>
);
};

And the button:

comopnents/Button.jsx

import { useState } from "react";

export const Button = () => {
const [clickedCount, setClickCount] = useState(0);

return (
<div>
<p>Click Count: {clickedCount}</p>
<button onClick={() => setClickCount(clickedCount + 1)}>Increment</button>
</div>
);
};

State is Not Reset when Changing Pages

The state is not reset when navigating between dynamic pages using this button. The behavior looks like this:

Handing State Reset

To reset the state between page loads, a component can make use of the useEffect hook, where the route change is a dependency.

To do so, we bring in next/router and use the asPath property as the useEffect dependency. Like this:

comopnents/Button.jsx

import { useState, useEffect } from "react";
import { useRouter } from "next/router";

export const Button = () => {
const [clickedCount, setClickCount] = useState(0);
const dynamicRoute = useRouter().asPath;

// Reset count to 0 on dynamic route change.
useEffect(() => setClickCount(0), [dynamicRoute]);

// ...
};

This gives us the reset behavior:

More Complex Scenarios

In some cases, you may be using useEffect for other purposes and with other dependencies. In these cases, you can either add additional logic and checks into your existing useEffect call, or you call simply add another call with different dependencies. That's the beauty of hooks in React.

useEffect(() => setClickCount(0), [dynamicRoute]);
useEffect(() => {
// do other stuff ...
}, [otherDeps]);

Resources

See the example project for a demo and to understand how it all fits together.

This StackOverflow answer helped me solve my particular issue, which was slightly more complex than this simple example.

Let's Connect

Keep Reading

Get user's Previous Path with NextJS Router

How to find the previous page a user visited before landing on the current page.

Feb 17, 2021

Open External next/link Links in a New Tab

Add a component that dynamically swaps between next/link and a native anchor tag, and decides how to write the target attribute, all based on the href property.

Jun 30, 2022

Custom XML Sitemap from a Catch All Route in Next.js

Building an XML sitemap in Next.js is a bit of an odd process. Here’s how I’ve done it by leveraging getStaticPaths methods from page components.

Aug 02, 2022