next/router → next/navigationPage Router import { useRouter } from "next/router"; export default function PostPage() { const router = useRouter();...
axios를 버리고 fetch와 QueryClient를 선택한 이유프로젝트를 Pages Router에서 App Router로 마이그레이션하면서 가장 많이 고민한 부분은 "데이터를 어떻게 가져올 것인가" 였다.기존에는 axios로 모든 요청을 처리했고, 그게 당연하다고 생각했다. 하지만 App Router로 전환하면서 두 가지 큰 변화를 겪었다.서버 컴포넌트에서는 fetch를 써야 Next.js의 캐싱이 작동한다클라이언트 컴포넌트의 비동기 상태는 React Query(TanStack Query)의 QueryClient로 관리한다Pages Router + axiosPages Router 시절의 데이터 패칭은 단순했다.// pages/posts/index.jsx export async function getServerSideProps() { const res = await axios.get('https://api.example.com/posts')...
App Router를 이해할 때 가장 먼저 봐야 하는 것들Next.js에서 Page Router를 쓰다가 App Router로 넘어오면 처음에는 폴더 구조가 바뀐 것처럼 보인다.pages/index.tsx가 app/page.tsx가 되고,pages/blog/[id].tsx가 app/blog/[id]/page.tsx가 된다.겉으로 보면 단순한 라우팅 방식의 변화처럼 느껴진다.하지만 실제로 App Router를 써보면 핵심은 폴더 구조가 아니다.더 중요한 변화는 렌더링을 바라보는 관점이다.Page Router에서는 보통 페이지 단위로 생각했다.이 페이지는 SSR로 할까? 이 페이지는 SSG로 할까? 이 페이지는 클라이언트에서 데이터를 가져올까?반면 App Router에서는 조금 더 세밀하게 생각하게 된다.이 컴포넌트는 서버에서 실행돼도 되는가?...
CSS는 언제 동작하나브라우저 기준으로 CSS는 대략 이렇게 동작한다.HTML 다운로드 → CSS 다운로드 → CSSOM 생성...
React를 처음 사용할 때는 대부분 상태를 useState로 관리한다.const [value, setValue] = useState(''); 값이 바뀌면 React가 다시 렌더링하고, UI는 그 상태를 기준으로 업데이트된다.이게 React의 기본 흐름이다.하지만 모든 값을 state로 관리하는 게 항상 좋은 선택은 아니다. input에 focus 주기DOM 크기 측정하기이전 값 기억하기부모 컴포넌트에서 자식 input을 제어하기같은 작업은 state보다 ref가 더 적합한 경우가 많았다.이때 사용하는 Hook이 useRef다.useRef란useRef는 렌더링 사이에서 값을 유지할 수 있는 객체를 만든다.const ref = useRef(initialValue);반환값은 이런 형태다.{ current: initialValue...
Critters를 공부하면서 가장 크게 바뀐 생각처음엔 CSS를 그냥 스타일 파일 정도로 생각했다.심지어 JS 최적화에 비해 덜 중요하다고 느꼈다.왜냐면 대부분 성능 이야기를 하면번들 크기hydrationReact 렌더링같은 게 더 많이 보였기 때문이다. 근데 브라우저 렌더링 과정을 공부하면서 생각이 바뀌었다.특히 느낀 건 CSS는 생각보다 굉장히 강한 render-blocking resource라는 점이었다.브라우저는 CSS가 없으면 쉽게 화면을 못 그린다처음엔HTML 먼저 보여주고 CSS는 나중에 적용하면 되는 거 아닌가? 싶었다.실제 흐름은 보통HTML 파싱...
useInfiniteQueryuseInfiniteQuery는 페이지 단위 데이터를 가져올 때 사용하는 TanStack Query 훅이다.즉 전체 데이터를 한 번에 가져오는 게 아니라현재 페이지 데이터 가져오기 → 다음 페이지 요청 → 이어붙이기방식으로 동작한다.예를 들어게시글 무한스크롤댓글 목록상품 리스트SNS 피드같은 UI에 적합하다.기본 구조const {...
모든 페이지를 미리 만드는 건 생각보다 비싸다예를 들어 상품 페이지가 있다고 하자.상품 3만 개가 있다고 가정하면3만 개 HTML 생성이 필요하다.처음엔 그냥3만 번 만들면 되는 거 아닌가?라고 생각했다.근데 실제론- 빌드 시간 증가- 메모리 사용 증가- 서버 리소스 증가- 배포 시간 증가전부 연결된다.특히 작은 서버 환경이나 EC2 프리티어 같은 곳에 직접 배포해보면 체감이 온다.next build 자체가 무거워지고, 메모리 부족으로 프로세스가 죽기도 한다.실제로는 모든 페이지가 동일한 트래픽을 받지 않는다.예를 들어인기 상품 → 조회수 높음오래된 상품 → 거의 안 봄인데도 SSG만 사용하면 안 보는 페이지까지 전부 빌드 해야한다. 여기서 ISR의 필요성이 보이기 시작했다.ISR은 “필요할 때만 정적 생성”ISR(Incremental Static Regeneration)은 SSG 기반인데, 필요할 때만 페이지를 다시 생성한다.처음엔 이름이 좀 추상적이었다. 핵심은“빌드를 점진적으로 한다”문제 상황예를 들어id 1 ~ 25 → 인기 페이지 id 26 ~ 30000...
DAL(Data Access Layer)프로젝트 규모가 작을 때는 보통 페이지나 컴포넌트 안에서 바로 인증 검사를 한다.const user = await getUser(); if (!user) { redirect('/login');...
성능 최적화를 할 때 처음에는 Lighthouse 점수만 확인했다.하지만 실제 서비스에서는 Lighthouse 점수와 사용자 체감 성능이 항상 일치하지 않았다.개발 환경에서는 괜찮아 보여도 실제 사용자는 전혀 다른 조건에서 서비스를 사용한다.느린 네트워크저사양 디바이스모바일 브라우저캐시 상태 차이페이지 진입 경로 차이Lighthouse만으로 부족했던 이유Lighthouse는 성능 개선 방향을 잡는 데 유용하다. 하지만 기본적으로 정해진 테스트 환경에서 실행된다.반면 실제 서비스에서는 사용자마다 조건이 다르다.예를 들어 개발자 PC에서는 LCP가 1.5초로 나와도, 실제 모바일 사용자는 4초 이상 걸릴 수 있다.또 특정 페이지는 전체 평균은 괜찮아 보여도, 일부 저사양 디바이스 사용자에게만 CLS가 높게 발생할 수 있다.이런 문제는 Lighthouse만으로는 발견하기 어렵다.그래서 운영 단계에서는 RUM, 즉 Real User Monitoring이 필요하다.기본 사용 코드'use client'; import { useReportWebVitals } from 'next/web-vitals'; export function WebVitals() {...
Next.js Metadata 시스템App Router에서는 직접 를 조작하기보다,metadata 객체를 선언적으로 관리한다.import type { Metadata } from 'next'; export const metadata: Metadata = { title: 'My Blog',...
단순히 의 wrapper처럼 보인다.하지만 실제로는이미지 최적화lazy loadingresponsive imageCLS 방지포맷 최적화같은 작업이 내부적으로 같이 처리된다.왜 대신 Image를 사용하는가초기에는 로도 충분하다고 생각했다.그러나 img는 원본 이미지 그대로 전송모바일에서도 초고해상도 이미지 다운로드화면 밖 이미지까지 모두 요청이미지 로딩 전 layout shift 발생같은 문제가 쉽게 생긴다.특히 콘텐츠 서비스나 커머스에서는 이미지 개수가 많아질수록네트워크 비용초기 렌더링 속도사용자 체감 성능차이가 꽤 커졌다.이미지 최적화를 브라우저에게 맡기지 않고 프레임워크 차원에서 처리하는 방식이 훨씬 안정적이었다.자동 최적화next/image는 브라우저와 디바이스 환경에 맞춰 이미지를 최적화한다.대표적으로이미지 리사이즈포맷 최적화(WebP/AVIF)lazy loadingCLS 방지responsive image 생성같은 작업을 자동으로 처리한다.중요한 건 “같은 이미지라도 사용자 환경마다 다른 이미지가 전달된다”는 점이다.예를 들어 모바일에서는 작은 이미지를, 고해상도 디스플레이에서는 더 큰 이미지를 내려준다.이 차이가 모바일 성능에서 꽤 크게 체감됐다.CLS 방지일반 는처럼 크기를 지정하지 않으면,이미지가 로드되기 전까지 브라우저가 공간 크기를 모른다.그 결과텍스트 렌더링 → 이미지 로드 → 레이아웃 밀림현상이 발생한다.이게 CLS(Cumulative Layout Shift)다. 특히 모바일에서는 체감이 꽤 심했다.Image 컴포넌트는 width와 height를 통해 렌더링 전에 미리 공간을 확보한다....