import { useRouter } from 'next/router'; export default function Page() { const router = useRouter(); function changeQuery() { router.push({ pathname: '/page', query: { tab: '2' } }, undefined, { shallow: true }); } return ( <> <p>Current tab: {router.query.tab || '1'}</p> <button onClick={changeQuery}>Change Tab</button> </> ); }
Shallow routing in Next.js changes the URL and updates the router state without running data fetching methods like getServerSideProps again. This allows the component to re-render with new query parameters efficiently.
Using router.push with the third argument { shallow: true } correctly enables shallow routing. router.replace can also be used but is less common for shallow routing that adds history entries.
import { useRouter } from 'next/router'; import { useEffect, useState } from 'react'; export default function Page() { const router = useRouter(); const [tab, setTab] = useState(router.query.tab || '1'); useEffect(() => { setTab(router.query.tab || '1'); }, []); function changeTab() { router.push({ pathname: '/page', query: { tab: '2' } }, undefined, { shallow: true }); } return ( <> <p>Current tab: {tab}</p> <button onClick={changeTab}>Change Tab</button> </> ); }
The useEffect hook runs only once because of the empty dependency array. It does not respond to changes in router.query, so the tab state does not update when shallow routing changes the URL.
Shallow routing updates the URL and component state but does not trigger Next.js data fetching methods like getServerSideProps or getStaticProps again. This means data may not refresh automatically.
router.query.tab after shallow routing?import { useRouter } from 'next/router'; import { useEffect } from 'react'; export default function Page() { const router = useRouter(); useEffect(() => { console.log('Tab query:', router.query.tab); }, [router.query.tab]); function changeTab() { router.push({ pathname: '/page', query: { tab: '3' } }, undefined, { shallow: true }); } return <button onClick={changeTab}>Change Tab</button>; }
When shallow routing updates the URL query, router.query reflects the new query parameters immediately, triggering the useEffect and logging '3'.