6월, 2026의 게시물 표시

React: 'Rendered more hooks than during the previous render' 훅 호출 순서 에러 해결법

이미지
3초 요약: 이렇게 고치세요 원인: React가 훅을 이름이 아니라 "호출된 순서"로 추적하는데, 조건문·조기 반환 때문에 렌더링마다 훅 호출 개수가 달라져서 발생 해결: 모든 훅 선언을 컴포넌트 최상단, 조기 반환(return)보다 위로 이동 / 조건은 훅 바깥이 아니라 훅 내부 로직으로 넣기 주의: 훅 자체를 if 로 감싸는 건 금지지만, 훅 내부에서 조건문을 쓰는 건 정상적으로 허용되는 패턴 useEffect(() => { if (isLoggedIn) analytics.logPage(); // 조건은 훅 안으로 }, [isLoggedIn]); ↓ 왜 이런 에러가 나는지 원리 보기 React 컴포넌트에서 조건에 따라 다른 화면을 먼저 보여주려고 조기 반환(early return)을 쓰다 보면 'Rendered more hooks than during the previous render' 에러를 만나는 경우가 있습니다. 이 에러가 왜 발생하는지, 그리고 훅 호출 규칙을 지키면서 문제를 해결하는 방법을 정리합니다. 왜 'Rendered more hooks' 에러가 발생하는가 이 에러의 근본적인 원인은 "리액트가 훅의 순서와 개수를 기억하는 방식"에 있습니다. 리액트 내부적으로 컴포넌트 내의 훅들을 상태 기억을 위해 링크드 리스트(Linked List) 구조로 관리합니다. 즉, 리액트는 훅을 고유한 이름이 아닌 "호출되는 순서"대로 매칭하여 값을 추적합니다. 조건문( if )이나 조기 반환( return )문 때문에 특정 렌더링에서 훅의 실행 순서가 뒤바뀌거나 누락되면, 리액트는 이전 상태와 매칭하는 데 실패하여 즉시 렌더링 크래시(컴파일 거부)를 발생시킵니다. 로딩 중일 때만 조기 return을 걸어두는 패...

Next.js App Router Styled-components 적용 에러 및 해결법

이미지
3초 요약: 이렇게 고치세요 원인: App Router 컴포넌트는 기본이 서버 컴포넌트라서, 클라이언트 런타임에 스타일 태그를 주입하던 styled-components 방식과 충돌해 FOUC(스타일 없는 화면)나 빌드 에러가 발생 해결: next.config.js 에 compiler.styledComponents: true 설정 + 서버에서 스타일을 수집하는 레지스트리 컴포넌트로 루트 레이아웃 감싸기 주의: 다크모드처럼 초기 테마 값을 서버가 미리 알아야 하는 스타일일수록 이 문제를 더 크게 체감함 // next.config.js compiler: { styledComponents: true } ↓ 왜 이런 에러가 나는지 원리 보기 Next.js App Router에서 Styled-components를 도입하면 첫 페이지가 로드될 때 스타일이 전혀 적용되지 않은 날 것의 HTML이 노출되다가 잠시 뒤 스타일이 입혀지는 FOUC(Flash of Unstyled Content) 현상이나 컴파일 에러를 겪게 됩니다. 이 문제가 생기는 원인과, App Router에서 오류 없이 연동하는 방법을 정리했습니다. 왜 App Router에서 Styled-components 에러가 날까 기존의 Styled-components는 클라이언트 사이드 런타임에 스타일 태그를 생성하고 자바스크립트로 이를 DOM에 주입하는 구조입니다. 하지만 Next.js App Router의 컴포넌트들은 기본적으로 서버 컴포넌트(Server Components)입니다. 즉, 자바스크립트가 브라우저에 도달하기도 전에 서버에서 HTML을 미리 해석하고 렌더링을 끝냅니다. 이 과정에서 Styled-components가 동적으로 생성한 스타일 시트가 정적 HTML 파일에 포함되지 않아 스타일이 완전히 깨진 형태로 전달되는 것입니다. 특히...

TypeScript 'Type is not assignable' 에러 원인 및 해결법

이미지
3초 요약: 이렇게 고치세요 원인: 넓은 타입( string )을 좁은 타입(유니온 리터럴)에 그대로 대입하려 하거나, 정의에 없는 잉여 프로퍼티가 든 객체 리터럴을 직접 대입해서 발생 해결: as 로 좁혀서 단언 / 객체는 중간 변수에 담았다가 대입 / 유니온 타입은 typeof · in 으로 분기해서 좁히기 주의: as 단언은 컴파일러 검사를 우회하는 것이라 실제로 그 타입이 맞는지는 개발자가 책임져야 함 userStatus = inputStatus as UserStatus; // string -> 리터럴 유니온 ↓ 왜 이런 에러가 나는지 원리 보기 타입스크립트 코딩을 할 때 가장 자주 마주치는 경고가 "Type 'A' is not assignable to type 'B'" (A 타입을 B 타입에 할당할 수 없습니다)일 겁니다. 언뜻 데이터 구조가 똑같아 보이는데 왜 불일치 경고가 나는지, 실전에서 타입을 좁혀 해결하는 방법을 정리했습니다. 왜 'not assignable' 에러가 발생하는가 이 에러의 본질은 "타입 호환성(Type Compatibility)의 규칙 위반"에 있습니다. 타입스크립트는 정적 컴파일 단계에서 값이 안전하게 대입될 수 있는지 검사합니다. 상위 개념의 넓은 타입에 하위 개념의 구체적인 타입을 넣는 것은 안전하지만(예: string 에 "admin" 리터럴 대입), 반대로 더 넓은 범주의 타입을 구체적인 타입 칸에 강제로 집어넣으려고 할 때 컴퓨터는 런타임 크래시를 우려해 할당 거부 경고를 내보냅니다. API 응답 값을 그대로 유니온 타입 변수에 넣으려다가 이 에러를 처음 마주치는 경우가 많습니다. 타입 할당 가능 범위 시각화 허용...

Next.js App Router에서 getServerSideProps 대체 및 데이터 페칭법

이미지
3초 요약: 이렇게 고치세요 원인: App Router는 서버 컴포넌트에서 직접 async/await를 쓸 수 있어 getServerSideProps / getStaticProps 가 아예 없어짐 해결: 빌드 시 캐싱(SSG) → 기본 fetch / 매 요청 최신화(SSR) → { cache: 'no-store' } / 주기 갱신(ISR) → { next: { revalidate: N } } 주의: getServerSideProps 안에 있던 인증 체크 로직은 이제 컴포넌트 함수 내부나 미들웨어로 옮겨야 함 const res = await fetch(url, { cache: 'no-store' }); // SSR과 동일하게 매번 재요청 ↓ 왜 이런 에러가 나는지 원리 보기 Next.js 13 이상에서 App Router가 표준이 되면서, Pages Router에서 쓰던 getServerSideProps 와 getStaticProps 가 더 이상 동작하지 않습니다. 두 함수가 사라진 설계적 이유와, 이를 대체하는 데이터 패칭 방식을 정리했습니다. 왜 getServerSideProps와 getStaticProps가 사라졌을까 과거 Next.js는 페이지 컴포넌트 내부에서만 특정 정적 함수( getServerSideProps 등)를 실행하여 데이터를 미리 받아온 뒤, 이를 컴포넌트의 props 로 넘겨주는 복잡한 직렬화 구조를 가졌습니다. 이로 인해 컴포넌트 간 깊이가 깊어지면 'Props Drilling(프로퍼티 대물림)'이 심해져 코드 관리가 몹시 까다로웠습니다. App Router 환경에서는 서버 컴포넌트(Server Component)가 표준이 됨에 따라 컴포넌트 내에서 직접 비동기 함수(async/await)를 작성할 수 있게 되었습...

TypeScript: 'Element implicitly has an 'any' type' 동적 객체 키 에러 해결법 (keyof & Record & Index Signature)

이미지
3초 요약: 이렇게 고치세요 원인: string 타입 변수로 객체 키에 접근하면 그 변수가 실제로 어떤 키를 담을지 컴파일 시점에 알 수 없어서 발생 해결: 키가 고정돼 있으면 as keyof typeof 객체 단언 / 키가 계속 늘어나면 인덱스 시그니처( [key: string]: Type ) 또는 Record<string, Type> 주의: API 응답 JSON을 그대로 순회하며 key로 값을 꺼내 쓸 때 특히 자주 마주치는 에러 const safeKey = key as keyof typeof USER_ROLES; return USER_ROLES[safeKey]; ↓ 왜 이런 에러가 나는지 원리 보기 자바스크립트에서는 문제없이 동작하던 동적 객체 키 접근 코드가 TypeScript로 옮기면 'Element implicitly has an any type' 경고를 띄우는 경우가 많습니다. 이 경고가 발생하는 이유와, 상황별로 쓸 수 있는 해결 방법 세 가지를 정리합니다. 타입스크립트는 왜 동적 키 접근을 에러로 잡는가 타입스크립트의 가장 큰 목적은 컴파일 단계에서 타입 안정성을 확보하는 것입니다. 예를 들어, 객체에 어떤 키가 존재할지 예측 불가능한 상황에서 임의의 변수를 문자열 키로 집어넣어 접근하려고 하면, 타입스크립트는 해당 결과값이 존재하지 않을 수 있어 위험( undefined 가능성)하다고 판단합니다. 그래서 기본값인 any 타입으로 암묵적으로 처리하며 경고를 내뿜게 되는 것입니다. API 응답으로 받은 JSON 객체를 그대로 순회하면서 key로 값을 꺼내 쓸 때 특히 자주 마주치는 에러입니다. TypeScript의 엄격한 키 매핑 구조 동적 변수 키 (컴파일 차단) const key: string 으로 선언된...

Next.js 이미지 컴포넌트(next/image) width/height 강제 에러 우회법

이미지
3초 요약: 이렇게 고치세요 원인: next/image 는 레이아웃 흔들림(CLS)을 막으려고 width · height 를 미리 요구하는데, 반응형으로 늘어나는 이미지는 고정 픽셀을 줄 수 없어서 발생 해결: 부모를 position: relative 로 잡고 fill 속성 사용 / 데이터 절약이 필요하면 sizes 속성 추가 / 원본 비율만 아는 외부 이미지는 가상 비율값 + height: auto 주의: fill 만 쓰면 뷰포트와 무관하게 가장 큰 원본을 그대로 받아오므로, 모바일 트래픽이 걱정되면 sizes 를 꼭 같이 지정할 것 <div style={{ position: 'relative', width: '100%', height: '300px' }}> <Image src="/hero.webp" alt="배너" fill style={{ objectFit: 'cover' }} /> </div> ↓ 왜 이런 에러가 나는지 원리 보기 Next.js에서 반응형 웹을 구현할 때 이미지 컴포넌트( next/image )를 쓰면 가로( width )와 세로( height )를 필수로 지정하라는 에러를 마주하게 됩니다. 고정 크기가 아니라 화면 너비에 맞춰 늘어나는 이미지를 쓰고 싶을 땐 이 제약을 우회할 방법이 필요한데, 상황별로 정리해 봤습니다. Next.js는 왜 가로/세로 크기 지정을 강제하는가 Next.js의 next/image 컴포넌트가 일반 <img> 태그보다 강력한 이유는 웹 성능을 자동으로 최적화해 주기 때문입니다. 그중 핵심이 바로 CLS(Cumulative Layout Shift: 누적 레이아웃 이동) 방지입니다. 이미지가 로드되기 전...

React 18/Next.js의 무한 루프 에러: useEffect 의존성 배열 지옥 탈출법

이미지
3초 요약: 이렇게 고치세요 원인: useEffect 가 렌더링마다 새로 만들어지는 객체/배열을 의존성 배열에 그대로 넣거나, 이펙트 내부에서 그 의존성 자신을 수정해서 발생 해결: 객체는 원시값(문자열/숫자)으로 분해해서 의존성에 넣거나 useMemo 로 캐싱 / 최초 1회만 실행할 로직은 의존성 배열을 빈 배열로 주의: API 응답 배열/객체를 그대로 의존성에 넣는 실수가 실무에서 가장 흔함 — 참조가 매번 바뀌어 얕은 비교에 걸림 useEffect(() => { fetchUserData(user); }, [user.type]); // 객체 통째로 X, 원시값만 ↓ 왜 이런 에러가 나는지 원리 보기 React나 Next.js로 컴포넌트를 개발하다가 브라우저가 갑자기 멈추거나, 개발자 도구 콘솔에 수천 개의 API 요청이 찍히며 과부하가 걸린 경험이 있으실 겁니다. 이런 '무한 렌더링 루프'는 거의 대부분 useEffect 훅과 의존성 배열(Dependency Array)의 잘못된 설계 때문에 생깁니다. useEffect 무한 루프는 왜 발생하는가 useEffect 훅은 컴포넌트가 렌더링된 이후 특정 상태의 변화에 따라 부수 효과(Side Effect)를 실행합니다. 이때 상태의 변화를 감지하는 기준이 바로 의존성 배열입니다. 무한 루프는 보통 이런 순서로 만들어집니다. 컴포넌트가 렌더링됩니다. useEffect 가 실행되고 내부에서 상태(State)를 업데이트합니다. 상태가 바뀌었으므로 컴포넌트가 다시 렌더링됩니다. 의존성 배열의 값이 바뀌었다고 판단되어 useEffect 가 또 실행됩니다. 2번~4번 과정이 무한히 반복되며 브라우저가 마비됩니다. API 응답으로 받은 배열이나 객체를 그대로 의존성 배열에 넣었다가 이 증상을 ...