개발자
넥스트js 13 app라우터를 사용중입니다 A라는 SeverSideRendering페이지에서 fetch를 이용해서 get을 서버에 요청해서 Db를 받아오고 있습니다 B라는 페이지에서는 버튼을 누르면 DB를 변경시켜줍니다 B페이지에서 버튼을 눌렀을때 A페이지의 데이터가 바로바로 변경이 안되는데 무슨이유인지 궁금하고 이것을 해결하는 방법이 궁금합니다
답변 3
인기 답변
안녕하세요. 일단 제가 이해한 상황이 맞는지 확인부터 해볼게요. "B 페이지에서 DB로의 mutation 요청을 수행한 뒤, A 페이지로 Client Side Navigation(<Link> Component 또는 useRouter() Hook)을 통해 이동했을 때 A 페이지에서 변경된 데이터가 반영되지 않은 상태로 보인다." 가 맞나요? 제가 이해한 상황이 맞다면, Next.js의 Router Cache라는 캐싱 메커니즘 때문에 곤경에 처하신 것 같아요. Router Cache의 동작에 대한 자세한 메커니즘은 공식 문서를 참고해 보세요. (https://nextjs.org/docs/app/building-your-application/caching#router-cache) 여하튼 메커니즘은 그렇다 치고, 해결 방법은 크게 2가지가 있어요. (이것도 공식 문서에 있는 내용입니다. 위 링크 타고 들어가 보시면 금방 찾으실 거예요.) 1. Server Action에서 revalidatePath 또는 revalidateTag라는 함수를 호출한다. 2. useRouter() Hook의 router.refresh 함수를 호출한다. router.refresh는 내가 무효화하고자 하는 캐싱된 페이지 경로를 따로 명시할 수 없어서 현재 질문자님 상황에서는 적절해 보이지 않는 것 같아요. (현재 머물러있는 캐싱된 페이지 경로에 대한 무효화만 가능) 그래서 결론은 Server Action을 사용하시면 될 것 같은데요, 제가 첨부 드리는 예시 코드를 참고해서 작성해 보시면 좋을 것 같네요. 말 그대로 예시 코드라, revalidatePath 동작을 좀 더 강조해 보이기 위해 mutation은 Client Side에서 진행하고 revalidatePath만 Server Side(Server Action)에서 진행하는 형태로 짜봤는데요, 사실 가능하다면 mutation과 revalidatePath를 모두 Server Action에서 진행하는 게 좀 더 일반적인 형태긴 합니다. 이것도 Server Action에 대한 공식 문서를 한 번 참고해 보세요. (https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
// src/app/A/page.tsx export const dynamic = 'force-dynamic'; export default async function Page() { const response = await fetch('API 경로'); const data = await response.json(); // 받아온 data를 보여준다. return <></>; } // src/app/B/page.tsx 'use client'; import { revalidatePathAction } from '../../actions/revalidatePathAction'; export default function Page() { const mutation = async () => { await fetch('API 경로', { method: 'POST', body: JSON.stringify({}), }); }; return ( <button onClick={async () => { await mutation(); revalidatePathAction('/B'); }} > mutation하고 revalidatePathAction하기 </button> ); } // src/actions/revalidatePathAction.ts 'use server'; import { revalidatePath } from 'next/cache'; export async function revalidatePathAction(page: string) { revalidatePath(page); }
인기 답변
앱라우터 자체가 워낙 뒷단에서 여러가지 일을 마법같이 처리하고 있다보니 동작의 원인을 파악하기 어려운 경우가 많습니다. 따라서 정확한 개발환경과 시도한 상황을 설명해주셔야 도움을 드릴 수 있습니다. 예컨대 next.js는 개발환경과 프로덕션환경 간의 동작 차이도 큽니다. 지금 설명해주신 현상만 생각해보자면 next.js의 app router의 경우 그 구조상 너무 많은 데이터페칭 요청이 생기기 쉽다는 문제점이 있습니다. 예컨대 이런 상황을 생각할 수 있을거에요 A 페이지에서도 "우리백엔드/상품리스트" 라는 api 의 응답값이 필요한데 B 페이지에서도 똑같이 "우리백엔드/상품리스트" api의 응답값이 필요한 경우가 있겠죠? 이러한 경우 비효율적인 데이터페칭요청이 많이 생길 수 있다는 성능적인 위험을 가지게됩니다. 그래서 next.js의 app router는 자신들의 사용예시에 맞게 사용된 fetch 를 이용한 데이터페칭 요청에 대하여 그 결과를 인메모리 캐싱을 통하여 서버에 저장해두며 이러한 내부스토어 캐싱 옵션이 모든 요청에 대해 기본적으로 수행됩니다. 따라서 작성자님이 실제로 DB를 변경하셨더라도 실제로는 캐싱된 데이터를 보고 있기 때문에 이전 데이터를 보게되었을 가능성을 예상할 수 있습니다. 이러한 문제의 해결책은 당연하지만 내부스토어 캐싱 옵션을 사용하지 않는 것을 생각할 수 있는데요 사용하지 않는 옵션을 주시면 되겠습니다. 만약 그러한 작업을 이미 수행 하였는데도 안되시는 상황이라면 유감이네요.. 관련 이슈가 있는지 찾아보시고 없다면 한번 이슈로 올려보시면 될 것 같습니다.
익명
작성자
2024년 01월 13일
제가 만약 페이지 제거 버튼을 누르고 페이지 제거가 db에서도 되고 view에서도 바로 된다면 리렌더링이 됐다고 볼 수 있나요?
유길종
프론트엔드 개발자 • 2024년 01월 13일
리렌더링 관점에서 접근하시는 건 좋은 생각이 아닐 확률이 높아보입니다. 또 제가 생각한 케이스가 작성자님 케이스에 정확히 해당하는지도 모르는 상태입니다. 먼저 시도해볼 수 있는 솔루션은 캐싱을 사용하지 않는 것입니다.
지금 가입하면 모든 질문의 답변을 볼 수 있어요!
현직자들의 명쾌한 답변을 얻을 수 있어요.
이미 회원이신가요?
지금 가입하면 모든 질문의 답변을 볼 수 있어요!