안녕하세요. Boaz 입니다.
총 4번의 이직을 거치며 다양한 스타트업을 경험 했고, 라인에서 일하다 얼마전 퇴사한 8년 차 프론트엔드 엔지니어입니다.
다양한 프로젝트에서 Next.js 를 활용하며, 저는 많은 시행착오를 겪었어요.
특히 실무에 적용하며 더 좋은 구조를 고민할 때, “왜 이렇게 구성해야 하지?”, “이 기능을 써도 되는 상황인가?” 같은 질문들이 쏟아졌고, 그때부터 단순한 사용법보다 '등장 배경과 동작 원리의 이해'가더 중요하다는 걸 느꼈어요.
이 강의는 단순히 Next.js를 ‘쓸 수 있게’ 만드는 것이 목적은 아니어요.
“왜 이렇게 설계 되었는가?”, “실무에서는 어떤 기준으로 선택해야 하는가?”를 함께 고민하고 싶은 분들을 위해 만들었어요.
단순히 쓸 줄 아는데 그치고 싶지 않았던 과거의 저와 같은 여러분에게, 이 강의가 정리된 관점과 기준을 제시해주는 나침반이 되었으면 합니다 😄
강의
수강평
- Next.js 까보기: "쓸 줄 아는 개발자"에서 "알고 쓰는 개발자"로
- Next.js 까보기: "쓸 줄 아는 개발자"에서 "알고 쓰는 개발자"로
- Next.js 까보기: "쓸 줄 아는 개발자"에서 "알고 쓰는 개발자"로
- Next.js 까보기: "쓸 줄 아는 개발자"에서 "알고 쓰는 개발자"로
- Next.js 까보기: "쓸 줄 아는 개발자"에서 "알고 쓰는 개발자"로
게시글
질문&답변
next Request Memoization과 react cache
안녕하세요. 먼저 깊이 있는 질문 주셔서 감사합니다.🤗바로 답변 드릴게요.적용 범위Request Memoization은 한 번의 서버 요청(=한 번의 React 트리 렌더링) 동안만 유효합니다. 같은 트리(레이아웃·페이지·서버 컴포넌트들) 안에서 같은 fetch(동일 URL+옵션)를 여러 번 호출해도 1번만 나갑니다. 하지만 /dashboard와 /home처럼 서로 다른 페이지 요청은 각각 별도 요청이므로 서로 공유되지 않습니다. 또한 React 컴포넌트 트리 밖(예: Route Handler)에는 적용되지 않습니다. 참고 - Next.js파라미터가 다르면?아니요. 메모이제이션 키는 **URL + fetch 옵션(메서드/헤더/바디 등)**이 동일할 때만 일치합니다. 쿼리 스트링이나 헤더가 달라지면 다른 요청으로 간주되어 중복 제거되지 않습니다. 추가로 메모이제이션은 GET만 대상입니다. 참고 - Next.jsaxios를 쓰면? 대안은 react의 cacheNext의 Request Memoization은 패치된 fetch에 붙는 최적화라서 axios에는 자동 적용되지 않습니다. 말씀하신대로 axios(또는 ORM/DB 클라이언트)를 써야 한다면, 해당 호출 함수를 react의 cache로 감싸면 비슷하게 “한 요청 내 중복 호출”을 최적화할 수 있습니다 참고 - Next.js
- 0
- 1
- 22
질문&답변
next.js 서버fetch 에러 fallback ui 구현 방법
답변이 늦었습니다 🙇♂우선 포인트 짚은 좋은 질문 주셔서 감사합니다. 답변 먼저 드릴게요 🤗가능합니다. “섹션 단위로만 실패 UI”를 띄우는 방법은 두 가지가 있어요.섹션 내부에서 에러를 ‘잡고’ 소프트-페일(fallback을 직접 렌더)App Router의 세그먼트 단위 에러 바운더리를 활용(= error.tsx), 섹션을 Parallel Routes로 분리말씀하신 방법 중에 error.tsx는 세그먼트 단위로 에러를 잡기에 추가적인 수정(라우팅 구조 관련)이 필요합니다. 우선 간단한 1번부터 자세히 설명드릴게요.1) 섹션 내부에서 처리(Soft fail)Server Component 안에서 fetch를 직접 try/catch로 감싸고, 실패 시 그 섹션만 대체 UI를 조건부 렌더링 하는 방법입니다. fetch는 네트워크 오류에서만 throw하고, HTTP 에러는 res.ok로 판별할 수 있어요.// SectionB.tsx (Server Component) export default async function SectionB() { try { const res = await fetch(process.env.API_URL + '/b', { cache: 'no-store' }); if (!res.ok) { // 섹션 전용 fallback return ; } const data = await res.json(); return ; } catch (err) { // 네트워크/파싱 등 예외 return ; } } 이 방식은 A, C는 정상 렌더, B만 fallback이 됩니다. 서버 액션이 아니어도 문제없어요. (Next 공식 가이드도 렌더 이후 비동기/이벤트성 에러는 바운더리가 못 잡으니 직접 처리하라고 안내합니다. (Next.js))장점: 구조 변경 없음.단점: “던지는(throw) 에러”를 경계로 분리해서 다루는 건 아님(즉, 바운더리가 아니라 “조건부 렌더”).2) 진짜 바운더리: Parallel Routes + error.tsxNext.js는 세그먼트 단위로 에러 바운더리를 둡니다. 같은 URL 안에서도 Parallel Routes(@slot) 를 쓰면 각 슬롯에 개별 error.tsx 를 둘 수 있어요. B만 실패해도 B 슬롯만 에러 UI가 나옵니다. (Next.js)예시 구조:app/dashboard/ page.tsx // 전체 레이아웃에서 슬롯을 배치 @a/page.tsx // SectionA @a/default.tsx @b/page.tsx // SectionB @b/error.tsx // B 전용 에러 UI @b/default.tsx @c/page.tsx // SectionC @c/default.tsx page.tsx(부모)에서 슬롯을 배치:export default function Dashboard({ a, b, c, }: { a: React.ReactNode; b: React.ReactNode; c: React.ReactNode }) { return ( {a} {b} {/* B만 실패하면 여기만 error.tsx로 대체 */} {c} ); } @b/error.tsx는 반드시 Client Component여야 하고, reset()으로 재시도 버튼을 만들 수 있습니다. (Next.js)'use client'; export default function Error({ error, reset, }: { error: Error & { digest?: string }, reset: () => void }) { return ( 섹션 B에서 오류가 발생했습니다. reset()}>다시 시도 ); } 장점: 진짜 “경계 격리”. 스트리밍 중에도 해당 슬롯만 대체 UI로 전환.단점: 라우팅(폴더) 구조를 바꿔야 함.참고: 말씀해주신 것처럼, 일반적인 커스텀 컴포넌트(react-error-boundary 등)를 JSX로 감싸는 것만으로는 서버 컴포넌트에서 던진 에러를 못 잡는 제약이 있습니다. App Router에선 세그먼트 error.tsx 를 두어야 안정적으로 잡혀요. (GitHub)어떤 방식을 고를까?빠른 적용/섹션별 단순 실패 처리 → 1) Soft fail (try/catch + 조건부 렌더)스트리밍/격리/리트라이까지 갖춘 정석 분리 → 2) Parallel Routes + error.tsx공식 문서 요약:에러 바운더리는 세그먼트 레벨에서 중첩 배치 가능(그 아래만 잡음), error.tsx는 클라이언트 컴포넌트여야 함. (Next.js)Parallel Routes는 각 슬롯별 독립 로딩/에러 상태를 제공. (Next.js)지금 쓰고 계신 페이지 구조에 맞춰 해결책을 선택하실 수 있을거여요. 리팩터링 없이 Soft fail 패턴으로 우선 적용하거나, Parallel Routes로 분리하는 파일 구조를 적용하는 방식으로요.
- 0
- 2
- 41
질문&답변
필터옵션이 많은 페이지에서도 서버 fetch를 사용하는게 맞을까요??
깊이있는 좋은 질문 주셔서 감사합니다. Next.js에서 필터가 많은 페이지를 구현할 때 서버 Fetch를 사용하는 것이 권장되는 이유는 서버 컴포넌트(RSC)의 장점인 초기 로드 시 빠른 응답과 낮은 클라이언트 번들 사이즈 때문입니다.그러나 질문하신 케이스처럼 필터가 많아 사용자가 빈번하게 데이터를 변경해야 할 경우에는 몇 가지 트레이드오프가 존재합니다.1. 서버 Fetch (RSC + route.push/replace)서버 컴포넌트와 서버 Fetch를 사용할 경우 다음과 같은 장단점이 존재합니다:장점초기 페이지 로딩이 매우 빠르고, SEO에 유리합니다.클라이언트 JS 번들 사이즈가 줄어들어 성능이 좋습니다.상태 관리 복잡도가 현저히 낮아집니다. (상태 관리를 서버가 대신합니다)단점필터 옵션을 변경할 때마다 매번 서버로 요청을 보내야 합니다.상태가 URL로 표현되기 때문에 router.push 또는 router.replace로 페이지가 다시 렌더링됩니다. 이는 페이지가 계속 새로 그려지는 느낌을 줍니다. (UX가 약간 투박할 수 있음)서버 Fetch 방식이 가장 적합한 경우는 필터가 상대적으로 자주 바뀌지 않고, URL 공유나 SEO가 중요한 상황입니다.예: 이커머스 상품 페이지, 검색 결과 페이지 등(또한 revalidatePath 등으로 캐시를 무효화하는 방법도 있습니다 :))2. 클라이언트 Fetch (React Query 등 클라이언트 상태 관리)필터 변경이 빈번한 경우 React Query와 같은 클라이언트 상태 관리 라이브러리를 사용하면 다음과 같은 특징이 있습니다.장점필터 변경 시 UI가 부드럽고 자연스럽습니다. UX가 더 뛰어납니다.클라이언트에서 데이터를 캐싱해두고 빠르게 응답을 제공합니다.페이지 전체가 아닌 필요한 부분만 리렌더링하므로 UX가 비교적 뛰어납니다.단점초기 JS 번들 사이즈가 늘어나고, 초기 로딩 속도는 서버 Fetch 대비 느려질 수 있습니다.데이터가 클라이언트 상태와 서버 상태로 나뉘게 되므로 관리가 복잡해질 수 있습니다.SEO 친화적이지 않을 수 있습니다. (데이터가 클라이언트에서 Fetch되므로)이 방식이 적합한 경우는 필터 변경이 매우 빈번하고, 실시간으로 부드럽게 변경되는 경험이 중요한 경우입니다.예: 관리자 페이지, 대시보드, 인터랙티브 데이터 분석 페이지 등 상황을 고려하셔서 적절한 기술을 사용하는게 가장 좋은 해결책인것 같습니다..! 리액트 쿼리 동작은 혹시 searchParams 가 키값에 포함되어 있나요??만약 그렇다면 아래와 같은 과정을 생각해볼 수 있을것 같아요. 기본적으로 리액트 쿼리는 Query Key가 변경될 때 자동으로 다시 fetch를 수행합니다.사용자가 직접 URL을 replaceState를 이용해 변경해도, Next.js Router나 React Router와 같은 라우터에서 제공하는 훅들이 URL 상태를 계속 관찰하고 있으며, URL 상태가 변경되면 라우터 상태가 변경됩니다.이로 인해 React Query 훅이 사용하는 queryKey(searchParams 등)가 변경되며, React Query가 변경을 감지하여 자동으로 fetch를 다시 요청합니다.React Query는 기본적으로 Query Key가 달라지면 새로운 요청을 자동으로 수행합니다.결론적으로 React Query가 사용하는 상태가 URL 상태와 연결되어 있다면, URL만 변경해도 자동으로 fetch 요청이 발생하는 것으로 추측할 수 있어요 :)
- 0
- 2
- 36
질문&답변
template.tsx 에서 서버 fetch 후 클라이언트 컴포넌트로 넘겨주면 싱크가 맞는 이유
이런 경우 문제 원인이 다양할 수 있어서요. 혹시 클라이언트 라우팅이 route segment 는 그대로이고, searchParams 가 바뀌는 형식일까요?(예를 들어 /gift-item -> /gift-list 의 이동이 아닌, /gift-item?id=1 -> /gift-item?id=2 처럼요)만약 위와 같은 이동(searchParams 만 바뀜)이라면 template.tsx 도 리렌더링이 발생하지 않아서 여쭤봅니다 🙏
- 1
- 1
- 31
질문&답변
layout 컴포넌트 내 클라이언트 컴포넌트
동일한 의미가 맞습니다.(Page.tsx 컴포넌트도 마찬가지 입니다.)정확하게 이해하신것 같아요..!다만, 강의에서 'use client' 지시어를 활용해 클라이언트 컴포넌트를 통해 해당 값에 접근해야 한다라는 말의 맥락은 Page.tsx 와 접근 방법이 차이점이 있다는 뜻은 아니어요.그보다는 'layout 에선' searchParams 에 접근할 수 없다. 하지만, Page.tsx 에서는 prop 으로 searchParams 등의 값에 접근할 수 있어서요. 이러한 차이점(둘다 서버컴포넌트지만, Page.tsx 에서는 searchParams 에 접근 가능한데, layout 에서는 접근 불가)에 대해 말씀드리고 싶었어요. 질문에서 말씀주신 것처럼 'use client'를 사용해서 접근하는 방식은 둘다 가능하기에 차이가 없어서요. 잘 이해하신 것 같아요 🤗혹시 추가로 궁금하신 점 있으시면 편하게 알려주셔요.
- 0
- 2
- 31
질문&답변
게시판 리스트 작성할 때 use client를 어디서부터 붙여야할지 모르겠어요
답변이 조금 늦었네요..!리스트 데이터를 클라이언트 상태로 어떻게 관리할지 고민할 때, 저도 같은 질문을 자주 하게 되어요. 특히 좋아요나 조회수처럼 계속 바뀌는 값이 들어간다면, 구조 설계에서 선택지가 애매하기도 해요.결론부터 말하자면, 리스트 전체를 통으로 관리하는 방식보다는, 각 레코드를 저장하고 개별 상태로 구독하는 방식이 가장 현실적이고 일반적인 선택인 것 같아요.그 이유는 다음과 같아요.먼저, 리스트 단위로 zustand에 통째로 저장하는 방식은 구현이 단순하다는 장점이 있어요. 초기 데이터 신뢰성도 높고, 서버에서 한번에 가져오기 때문에 깔끔하죠. 하지만 이 방식은 말씀주신 것처럼 한 레코드의 좋아요 수만 바뀌어도 전체 리스트가 다시 렌더링되기 때문에 성능에서 손해를 봅니다. 동적 상호작용이 많을수록 이 비용은 커져요.반면, 각 레코드를 Map 형태로 분리해 저장하면 레코드 단위로만 렌더링이 발생해요. 좋아요가 눌리거나 조회수가 늘어나더라도 해당 레코드만 변경되고, 나머지는 그대로 유지되어요. SSR로 리스트 전체를 내려준 뒤 클라이언트에서는 필요한 레코드만 다시 fetch하거나 상태를 갱신하면 되기 때문에, 초기 속도와 동적 업데이트 사이의 균형도 잡을 수 있어요.('use client' 가 되는 것과 SSR 여부는 별개여서요. 강의의 렌더링 파트를 보시면 조금 더 확실해지실 것 같아요 🙂 )조금 번거롭긴 하지만 결국 이 방식이 유지보수성과 성능, 유연성을 동시에 확보할 수 있는 구조인것 같아요. 실무에서 React 앱을 설계할 때도 이 방식을 주로 했던 것 같아서요.초기 데이터는 서버에서 리스트 형태로 내려받되, 클라이언트 상태에서는 Map 형태로 변환해 저장하고, 각각의 레코드를 zustand로 구독하는 구조를 추천해요. 그나마 적절한 타협점 인것 같아서요.
- 0
- 1
- 44
질문&답변
'왜 Next.js 가 필요할까?(기술적인 등장 배경)' 에서 언급하는 영상들이 무엇일까요?
안녕하세요 지환님 질문 주셔서 감사해요 아래와 같이 각 영상 안내드립니다 1번 비동기에 대한 영상https://youtu.be/OITMfwqmUNY?si=W_CcPkZ8PENPMHFd 2번 ssr 에 대한 영상https://youtu.be/D71ByEIBWEs?si=kdda_ciDD-RXaixx
- 0
- 2
- 89
질문&답변
Parallel Route를 사용한 모달에 대해 질문이 있어요.
정확하게 보셨어요 default.js를 잘 활용하면, 그와함께 경로 설계를 함께 바꾼다면 가능해요..!default.js는 슬롯이 비어 있을 때 보여 줄 기본 화면만 담당해서요.딥 링킹과 공유 가능한 URL을 얻으려면,모달을 @modal 같은 병렬 슬롯으로 분리한 뒤그 안에 (.) intercepted route를 두어야 합니다. 이렇게 URL 자체에 배경 경로를 포함시켜야 새로고침이나 직접 접근에서도 리스트 + 모달이 함께 복원되어서요. 다시 말해 default.js만으로는 해결되지 않고, 경로 설계를 함께 바꿔야 해요.
- 0
- 2
- 67
질문&답변
유튜브 영상과의 차이점 문의
유튜브에서 함께 공부해주셨군요 :)아래 4개가 인프런 강의에만 있는 영상입니다.router.push() 종료 시점을 잡는 방법?왜 route.ts 와 page.tsx 는 다른 폴더에 선언해야 할까? 왜 props 로 함수를 전달(Server -> Client Component)할 수 없을까?ISR 언제 사용해야 할까?또한 4월 중에 Composition patterns 에 대해 추가로 업데이트할 예정이어요.혹시 Next.js 안에서 강의가 필요한 주제를 말씀해주시면, 추가로 강의를 제작하여 업데이트 해볼게요. 🙏
- 0
- 1
- 149
질문&답변
자동화 스크립트 관련하여 질문있습니다.
맞아요. 다만 동적 라우팅 관련 처리는 기존 스크립트보다 좀 더 복잡할 수 있어서요 ㅎㅎ 제가 진행했던 것처럼 claude 활용해서 해보시면 힌트를 얻으실 수 있으실 거여요 하다가 잘 안되는 부분이 있다면 언제든지 또 질문 주셔요!
- 0
- 2
- 65