✏️ Next.js
[pages] Shallow Routing
category
✏️ Next.js
date
thumbnail
slug
next-js-pages-shallow-routing
author
status
Public
tags
pages router
summary
type
Post
Shallow Routing
getServerSideProps
/ getStaticProps
등을 다시 실행시키지 않고, 현재 상태를 잃지 않고 url을 바꾸는 방법상태는 유지하면서 url만 바꾸고 싶은 경우에 사용한다.
⇒ 사용자가 어떤 동작을 했고, 그 기록을 query로 남기고 싶을 때
⇒ query로 남기면 사용자가 새로고침을 해도 유지된다.
⇒ 하지만 Data fetching을 일으키고 싶지 않다면 shallow routing 사용!
url을 바꾸는 3가지 방식
location.replace(’url’)
: 로컬 state 유지 안 됨(리렌더)
router.push(url)
: 로컬 state 유지 / data fetching은 일어남
router.push(url, as, { shallow: true })
: 로컬 state 유지 / data fetching 안 일어남- 동일한 페이지에서 쿼리만 달라져야 함
- ex) data/info?name=Lami 는 가능한데 data/age처럼 쿼리가 아니라 아예 다른 페이지면 적용이 안 된다.
Example
전체 예시 코드
import { useRouter } from 'next/router';
import { useState } from 'react';
export async function getServerSideProps() {
console.log('server');
return {
props: {},
};
}
export default function ShallowRouting() {
const router = useRouter();
const [clicked, setClicked] = useState(false);
const { status = 'initial' } = router.query;
return (
<>
<h1>Clicked: {String(clicked)} </h1>
<h1>Status: {status}</h1>
<button
onClick={() => {
alert('edit');
setClicked(true);
location.replace('/shallow-routing?status=editing');
}}>
edit(replace)
</button>
<span> 로컬 state 유지 안 됨(리렌더)</span>
<br />
<button
onClick={() => {
alert('edit');
setClicked(true);
router.push('/shallow-routing?status=editing');
}}>
edit(router.push)
</button>
<span> 로컬 state 유지 / data fetching은 일어남</span>
<br />
<button
onClick={() => {
alert('edit');
setClicked(true);
router.push('/shallow-routing?status=editing', undefined, {
shallow: true,
});
}}>
edit(shallow)
</button>
<span> 로컬 state 유지 / data fetching 안 일어남</span>
</>
);
}
다음과 같이 한번에 각각의 경우를 확인하기 위한 예시이기에 전체 코드가 길다.
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2F980718df-dec2-4ed6-86a7-8523376d1275%2Fd5d9be41-97c4-42f9-80d9-cceca1fb0841%2FUntitled.png%3Fid%3D6a9ac1ef-0ca6-4394-aa8d-7c8983827d1b%26table%3Dblock%26spaceId%3D980718df-dec2-4ed6-86a7-8523376d1275%26expirationTimestamp%3D1720310400000%26signature%3DqpwMAT_nnv-O--wJgov4eFnpeAK2xsRi5Tv7YlHwINg?table=block&id=6a9ac1ef-0ca6-4394-aa8d-7c8983827d1b&cache=v2)
조금씩 나눠서 살펴보자.
먼저 실행 결과 화면을 보면 Clicked: false, Status: initial 이 있다. 이는 초기 상태를 뜻하는 화면이다.
Clicked 의 false 는
useState
의 초기값인 false이고, Status의 initial 은 router.query
를 통해 가져오지만 초기 상태는 initial 로 지정했다. 따라서 쿼리가 없다면 Status 의 상태(콜론 옆 문구)는 initial 이 된다.여기서 url을 바꾸는 3가지의 방법을 살펴보려 한다.
각 버튼을 누르면 alert로 edit을 띄우게 되며,
setState
함수를 통해 Clicked의 상태를 true로 바꾸고,/shallow-routing?status=editing 로 현재 페이지에서 쿼리를 가진 페이지로 이동하게 된다.
이때의 화면에 나오는 결과를 살펴보자.
아, data fetching이 일어나는지를 확인하기 위해
getServerSideProps
를 이용해서 터미널에 server 라는 메세지를 띄운다. 버튼을 눌러 페이지를 이동했을 때 터미널에 server 메세지가 뜬다면 data fetching이 일어났다는 뜻이다.1️⃣ location.replace
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2F980718df-dec2-4ed6-86a7-8523376d1275%2F1bdfda39-b02b-4751-b14c-dec052284692%2FUntitled.png%3Fid%3D81467099-fa03-4888-8349-bfbca08ae89f%26table%3Dblock%26spaceId%3D980718df-dec2-4ed6-86a7-8523376d1275%26expirationTimestamp%3D1720310400000%26signature%3DRNVBcKa1JAkeX9M2icp8s00XHFwp6ZpfByvOlwwaC_g?table=block&id=81467099-fa03-4888-8349-bfbca08ae89f&cache=v2)
전체 코드에서 해당 경우만을 나타내도록 잘라내었다.
import { useRouter } from 'next/router';
import { useState } from 'react';
export async function getServerSideProps() {
console.log('server');
return {
props: {},
};
}
export default function ShallowRouting() {
const router = useRouter();
const [clicked, setClicked] = useState(false);
const { status = 'initial' } = router.query;
return (
<>
<h1>Clicked: {String(clicked)} </h1>
<h1>Status: {status}</h1>
<button
onClick={() => {
alert('edit');
setClicked(true);
location.replace('/shallow-routing?status=editing');
}}>
edit(replace)
</button>
<span> 로컬 state 유지 안 됨(리렌더)</span>
</>
);
}
버튼을 누르자,
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2F980718df-dec2-4ed6-86a7-8523376d1275%2Ffcfd7cc1-6ec2-4b82-8590-2bc823380d7d%2FUntitled.png%3Fid%3D4d753412-9df7-4b4d-815a-5df02b943d3c%26table%3Dblock%26spaceId%3D980718df-dec2-4ed6-86a7-8523376d1275%26expirationTimestamp%3D1720310400000%26signature%3DNkmqB-5ENclpzGGteWfR53J1z17fddVol4f-T-cdyXk?table=block&id=4d753412-9df7-4b4d-815a-5df02b943d3c&cache=v2)
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2F980718df-dec2-4ed6-86a7-8523376d1275%2Fd61fd5a5-5e9a-4238-9b9c-411349738549%2FUntitled.png%3Fid%3D669c7651-4df5-4c69-bacf-4855c3c36463%26table%3Dblock%26spaceId%3D980718df-dec2-4ed6-86a7-8523376d1275%26expirationTimestamp%3D1720310400000%26signature%3D10U_yYujBXQLH0w4Zsplh1M3iP6_U2Ese-FGFDv9Hdg?table=block&id=669c7651-4df5-4c69-bacf-4855c3c36463&cache=v2)
- Clicked: false
- 버튼을 눌러
setState
함수가 동작해 true 로 바뀌었으나, 페이지가 리렌더 되어state
가 유지되지 않아 false 를 갖고 있다.
- Status: editing
- /shallow-routing?status=editing 로 이동했기에
router.query
에서staus
의 값을 저장하므로 editing을 갖고 있다.
- 터미널에서 server 출력
- 브라우저가 리렌더 되었으며
getServerSideProps
가 동작해 터미널에 server 를 출력했다.
2️⃣ router.push
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2F980718df-dec2-4ed6-86a7-8523376d1275%2Fc89e371f-37ce-41ab-9b42-b8d1b6c9569c%2FUntitled.png%3Fid%3D750c1120-db7d-4643-b543-febf11064408%26table%3Dblock%26spaceId%3D980718df-dec2-4ed6-86a7-8523376d1275%26expirationTimestamp%3D1720310400000%26signature%3Ds4xihN6Ck76Bm2UNOYUDA0aJPYdUSzKB597bj2CjDlw?table=block&id=750c1120-db7d-4643-b543-febf11064408&cache=v2)
import { useRouter } from 'next/router';
import { useState } from 'react';
export async function getServerSideProps() {
console.log('server');
return {
props: {},
};
}
export default function ShallowRouting() {
const router = useRouter();
const [clicked, setClicked] = useState(false);
const { status = 'initial' } = router.query;
return (
<>
<h1>Clicked: {String(clicked)} </h1>
<h1>Status: {status}</h1>
<button
onClick={() => {
alert('edit');
setClicked(true);
router.push('/shallow-routing?status=editing');
}}>
edit(router.push)
</button>
<span> 로컬 state 유지 / data fetching은 일어남</span>
</>
);
}
버튼을 누르자,
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2F980718df-dec2-4ed6-86a7-8523376d1275%2F34f0e7ed-b365-498d-9623-a91666d66b04%2FUntitled.png%3Fid%3Dabfc7852-cef0-4b9b-b4a9-c0f852e98582%26table%3Dblock%26spaceId%3D980718df-dec2-4ed6-86a7-8523376d1275%26expirationTimestamp%3D1720310400000%26signature%3D9o8ve_SoMEqQW0qBwE7z-u4Z-3q3qLatez4scpM26go?table=block&id=abfc7852-cef0-4b9b-b4a9-c0f852e98582&cache=v2)
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2F980718df-dec2-4ed6-86a7-8523376d1275%2F8ec681ee-7e17-4329-aa7b-6b39a847140f%2FUntitled.png%3Fid%3D4fec4cd1-82ac-4273-8dfa-cf41e2a989fd%26table%3Dblock%26spaceId%3D980718df-dec2-4ed6-86a7-8523376d1275%26expirationTimestamp%3D1720310400000%26signature%3DpESpvimvVtcDOmqr-MtSCoaOeMxOSFMetXuThuJlFr0?table=block&id=4fec4cd1-82ac-4273-8dfa-cf41e2a989fd&cache=v2)
- Clicked: true
- Status: editing
- 터미널에서 server 출력
⇒
router.push
는 리렌더링이 아니기 때문에 버튼 클릭을 통해 바뀐 state
는 유지가 되지만 data fetching이 일어나 터미널에 server 를 출력했다.3️⃣ shallow ⇒ router.push(url, as, { shallow: true })
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2F980718df-dec2-4ed6-86a7-8523376d1275%2F5dc689a3-45ea-42ba-946f-4cccd52e0ecc%2FUntitled.png%3Fid%3D49b8ae53-77fd-4f2e-8485-378ca48d77f3%26table%3Dblock%26spaceId%3D980718df-dec2-4ed6-86a7-8523376d1275%26expirationTimestamp%3D1720310400000%26signature%3DjF3GKVe09b5g3JvearObQEhxKN-WhXkG2QneUF4zH9o?table=block&id=49b8ae53-77fd-4f2e-8485-378ca48d77f3&cache=v2)
import { useRouter } from 'next/router';
import { useState } from 'react';
export async function getServerSideProps() {
console.log('server');
return {
props: {},
};
}
export default function ShallowRouting() {
const router = useRouter();
const [clicked, setClicked] = useState(false);
const { status = 'initial' } = router.query;
return (
<>
<h1>Clicked: {String(clicked)} </h1>
<h1>Status: {status}</h1>
<button
onClick={() => {
alert('edit');
setClicked(true);
router.push('/shallow-routing?status=editing', undefined, {
shallow: true,
});
}}>
edit(shallow)
</button>
<span> 로컬 state 유지 / data fetching 안 일어남</span>
</>
);
}
버튼을 누르자,
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2F980718df-dec2-4ed6-86a7-8523376d1275%2F80c22140-9f79-42c4-80bf-4ff04ea8de52%2FUntitled.png%3Fid%3D221801a9-1e64-4714-9ffd-a306a061f619%26table%3Dblock%26spaceId%3D980718df-dec2-4ed6-86a7-8523376d1275%26expirationTimestamp%3D1720310400000%26signature%3D_oDkzFmRvIxtDhH71hva2u03Xnz1EoHnnqA1r2PJzzY?table=block&id=221801a9-1e64-4714-9ffd-a306a061f619&cache=v2)
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2F980718df-dec2-4ed6-86a7-8523376d1275%2Ff96147db-e773-4841-b80e-919d9a8851ff%2FUntitled.png%3Fid%3D6b65440c-665c-4afa-a0b3-81e7b35c8324%26table%3Dblock%26spaceId%3D980718df-dec2-4ed6-86a7-8523376d1275%26expirationTimestamp%3D1720310400000%26signature%3D-DYe9sY9OAFFen-oVFkpfQaiycBRMwridEwHJOyZI5k?table=block&id=6b65440c-665c-4afa-a0b3-81e7b35c8324&cache=v2)
- Clicked: true
- Status: editing
- 터미널에 server 가 출력되지 않음
⇒ 클릭을 통해 바꾼
state
도 잘 갖고 있고, data fetching이 일어나지 않아 터미널에 server 가 출력되지 않았다.결론
처음에 말했다시피 Shallow Routing 은
getServerSideProps
/ getStaticProps
등을 다시 실행시키지 않고, 현재 상태를 잃지 않고 url을 바꾸는 방법이다.상태를 유지하며 쿼리를 통해 url을 바꾸고 싶을 때 사용할 수 있다.
아마 모달 같은 곳에서 주로 사용하지 않을까 싶다!