본문으로 건너뛰기

x-clone으로 Next.js 14 다시 공부하기

· 약 2분
Seung hyo, Lee
Front End Engineer @ Assistfit

회사에서 App Router로 CRM을 만들고 있지만, 일정에 쫓기다 보니 이해하지 못한 채 넘어간 부분이 많았다. 1월 한 달은 주말과 퇴근 후에 X(트위터) 클론을 만들면서 Next.js 14를 처음부터 다시 짚었다.

라우트 구조​

첫날은 화면 뼈대와 라우팅에 썼다. (beforeLogin), (afterLogin) 라우트 그룹으로 레이아웃을 나누고, 로그인, 회원가입, 글쓰기는 @modal 슬롯 안에 (.) intercepting route로 만들고, 사진 보기도 같은 슬롯에 모달로 띄웠다. 모달로 뜨는 화면도 각자 주소를 가지니 링크로 공유하거나 뒤로 가기로 닫는 동작이 자연스럽다. 회사에서 모달 페이지를 만들 때 default.tsx가 왜 필요한지 헷갈렸는데, 여기서 슬롯이 매칭되지 않을 때의 기본값이라는 걸 확실히 이해했다.

MSW와 React Query​

백엔드 없이 개발하려고 MSW를 붙였다. 브라우저용 워커와 함께 @mswjs/http-middleware로 Express 서버를 띄워서, 서버 컴포넌트의 fetch도 목 데이터를 받게 했다.

데이터는 React Query로 관리했다. 서버 컴포넌트에서 먼저 받아두고 클라이언트에 넘기는 방식이다.

const queryClient = new QueryClient();
await queryClient.prefetchInfiniteQuery({
queryKey: ['posts', 'recommends'],
queryFn: getPostRecommends,
initialPageParam: 0,
});
const dehydratedState = dehydrate(queryClient);

이걸 HydrationBoundary로 감싸면 클라이언트의 useSuspenseInfiniteQuery가 같은 키로 캐시를 바로 쓴다. 무한 스크롤은 react-intersection-observer로 마지막 요소가 보일 때 fetchNextPage를 부르게 했다. useQuery를 useSuspenseQuery로 바꾸니 로딩과 에러를 loading.tsx, error.tsx가 맡아서 컴포넌트 안의 분기가 사라졌다.

그 밖에 next-auth v5로 로그인을 붙이고, 게시글 작성을 useMutation으로 옮겼다. 지금은 좋아요의 optimistic update를 하기 전에 클릭 이벤트가 게시글까지 전파되는 문제를 막아 둔 상태다.

회사 코드에서는 next-auth를 걷어냈는데, 여기서는 백엔드가 세션 쿠키를 쓰는 구조라 그대로 썼다. 같은 도구라도 서버 구조에 따라 맞고 안 맞고가 갈린다는 걸 두 프로젝트를 동시에 하면서 느꼈다.