FEInterview Prep

Medium

이소모픽 레이아웃 이펙트라는건 없다

useIsomorphicLayoutEffect 는 사실 "서버에서 아무것도 안 함"을 우회로 표현한 패턴이다. 경고를 끄는 게 목적이라면 컴포넌트 자체를 클라이언트 전용으로 두는 게 더 정직한 답일 수 있다.

2025-08-12·7분 읽기
React
원문 보기 ↗

핵심 요약

useLayoutEffect 는 클라이언트에서 DOM 커밋 후 페인트 전에 실행되어 레이아웃 측정/수정에 사용된다. SSR에서는 DOM이 없어 실행 자체가 불가능 → 리액트가 경고를 띄움. useIsomorphicLayoutEffect 류는 "클라이언트면 useLayoutEffect, 아니면 useEffect"로 분기해 경고만 끄는 코드인데, 서버에서 useEffect 도 어차피 실행되지 않으므로 사실상 noop이다. 진짜 문제는 두 가지로 나뉜다: (1) 레이아웃을 "수정"하는 이펙트 → 컴포넌트를 클라이언트 전용(use client/dynamic import)으로 두는 게 맞다. (2) DOM 을 "읽기만" 하는 이펙트 → 서버에서 실행 안 돼도 안전하므로 경고만 무시해도 된다. "이소모픽" 별칭은 이 둘을 구분하지 않고 모두에게 동일한 회피책을 권한다는 점이 함정이다.

useLayoutEffectDOM 커밋 직후, 페인트 직전 에 동기로 실행되는 슬롯이다. 서버에는 DOM도 페인트도 없으므로 자연스럽게 실행되지 않는다. 따라서 "이소모픽"(서버·클라이언트 동일 거동)은 정의상 불가능하며, 흔히 쓰이는 useIsomorphicLayoutEffect경고 회피용 별칭일 뿐이다.

면접에서 "useEffect vs useLayoutEffect" 만 묻는 게 아니라, SSR 환경에서 어떻게 동작하나요? 까지 들어가는 질문이 늘고 있다. 이 글은 "왜 모두가 react-redux 의 임시 패치를 그대로 복사해 표준이 됐는가"를 추적해, 패턴을 외우지 말고 의도를 이해해야 한다는 교훈을 준다.

학습 포인트

면접 답변으로 연결할 학습 포인트입니다.

`useLayoutEffect` 가 정확히 언제 실행되는가

리액트의 라이프사이클을 시간순으로 보면:

  1. 렌더 함수 실행 → 가상 DOM 생성
  2. 실제 DOM 커밋
  3. useLayoutEffect 실행 (동기)
  4. 브라우저 페인트
  5. useEffect 실행 (비동기)

사용자에게 "잘못된 위치의 툴팁"이 한 프레임이라도 보이면 안 되는 경우 useLayoutEffect 가 필요하다.

paintcommit phasesynchronous effect
자주 하는 오해

useLayoutEffectuseEffect 를 "성능 차이"로만 이해. 실제 차이는 페인트와의 순서다.

SSR에서 `useLayoutEffect` 가 경고를 띄우는 이유

서버에는 DOM 도 페인트도 없으므로 레이아웃 이펙트는 실행되지 않는다. 그러면 "초기 HTML"과 "하이드레이션 후 의도한 UI" 사이 불일치가 생긴다 — 사용자가 잠깐 잘못된 위치의 툴팁을 본다는 뜻. 리액트의 경고는 "이 컴포넌트는 클라이언트 전용으로 두는 걸 고려하라"는 신호.

hydration mismatchSSR warningfirst paint
자주 하는 오해

경고를 노이즈로 간주하고 끄기. 경고 자체가 "UX 문제 가능성"을 알려주는 디버그 신호다.

`useIsomorphicLayoutEffect` 의 실체

import { useEffect, useLayoutEffect } from 'react';
const isClient = typeof document !== 'undefined';
export default isClient ? useLayoutEffect : useEffect;

서버 분기에서 useEffect 를 쓰지만 서버는 어차피 이펙트를 실행하지 않으므로 사실상 noop 의 별칭이다. 효과는 단지 "경고를 안 띄움".

noop aliaswarning suppressionreact-redux
자주 하는 오해

"서버에서 useEffect 가 동작하니까 안전하다"는 오해.

올바른 분류 — 수정 vs 읽기

이펙트 종류서버에서 안전한가권장 해법
레이아웃을 "수정" (위치 계산해 setState)아니오 — 잘못된 UI 노출컴포넌트 자체를 클라이언트 전용으로(use client / dynamic with ssr: false)
DOM 을 "읽기만" (트리 동기화 등)예 — 효과가 누적될 뿐서버에서만 경고 무시(useIsomorphicLayoutEffect 류 사용 가능)

핵심은 "내 이펙트는 첫 페인트의 정확성에 영향을 주는가" 한 줄.

client-only componentdynamic import ssr:falseDOM read vs write
자주 하는 오해

두 종류를 같은 도구로 처리. 수정형은 사용자에게 보이는 깨진 UI 를 만든다.

복사·붙여넣기로 굳어진 "표준"의 위험

react-redux 가 자기 사용 사례에서 "경고 끄기"용으로 만든 코드를 다른 라이브러리들이 그대로 복사 → Medium 글에 정리되어 검색 1순위 → 더 많은 사람이 또 복사. 이렇게 임의 결정이 사실상 표준이 된 사례다. 라이브러리 코드를 읽을 때도 "왜 이렇게 했는가"의 맥락이 더 중요하다는 교훈.

cargo cult programmingopen source provenance
자주 하는 오해

유명 라이브러리의 패턴이라는 이유로 무비판 수용. 원래 결정의 맥락을 따라가 보면 자기 코드엔 안 맞는 경우가 많다.

읽는 순서

  1. 1이론

    리액트 렌더/커밋/페인트 타임라인과, SSR 에서 이펙트가 실행되지 않는 이유를 정리.

  2. 2구현

    Next.js App Router 환경에서 (1) 클라이언트 전용 분리, (2) useIsomorphicLayoutEffect 패치, (3) 그냥 useEffect 로 다운그레이드 — 세 패턴을 같은 컴포넌트에 적용해 첫 페인트 차이를 캡처해 비교.

  3. 3실무

    사내 코드의 useIsomorphicLayoutEffect 사용 위치를 "읽기/수정"으로 분류해 부적절하게 쓰인 곳을 PR로 정리.

  4. 4설명

    동료에게 "이 경고는 노이즈가 아니라 신호다" 를 한 페이지로 설명할 수 있게 도식화.

면접 연결 질문

medium`useEffect` 와 `useLayoutEffect` 의 차이를 SSR 까지 포함해 설명해주세요.
힌트

[감점 답변] "하나는 동기, 하나는 비동기". [좋은 답변] (1) 시점: useLayoutEffect 는 DOM 커밋 직후·페인트 전 동기, useEffect 는 페인트 후 비동기. (2) 용도: 측정/수정해야 깜빡임 없는 경우 → useLayoutEffect, 그 외 → useEffect. (3) SSR: useLayoutEffect 는 서버에서 실행 안 됨 → 클라이언트 전용으로 두거나 동적 import 로 분리. useEffect 도 서버에서 실행 안 되지만 첫 페인트 정확성에 영향 적음.

hard`useIsomorphicLayoutEffect` 가 진짜로 해주는 일은 무엇인가요?
힌트

[감점 답변] "서버에서도 useLayoutEffect 처럼 동작한다". [좋은 답변] 서버에서도 클라이언트에서도 거동을 같게 만드는 게 아니다. 단지 서버 분기에서 useEffect 를 쓰는 모양만 바꿔 리액트의 경고를 우회하는 것. 서버는 어떤 이펙트도 실행 안 한다. 따라서 "레이아웃을 수정해야 하는 컴포넌트" 라면 클라이언트 전용으로 두는 게 더 정직하다.

hardNext.js App Router 에서 `useLayoutEffect` 경고가 떴습니다. 어떻게 분류해서 해결하나요?
힌트

[감점 답변] "useEffect 로 바꾼다". [좋은 답변] (1) 읽기만 하는 이펙트(DOM 측정·내부 트리 동기화)면 그대로 두고 경고만 무시 가능. (2) 레이아웃을 setState 하는 이펙트"use client" 컴포넌트로 분리하거나 dynamic(() => import('X'), { ssr: false }). (3) 깜빡임이 허용되면 useEffect 로 다운그레이드 가능 — 단, 첫 페인트 위치가 잘못 보이는 트레이드오프 인지.

자기 점검

왜 `useIsomorphicLayoutEffect` 가 "이소모픽이 아니다"라고 말하는지 한 줄로 설명해보세요.
서버noop경고 회피동일 거동 아님
자주 하는 오해

"두 환경에서 같은 코드가 돈다"고 오해. 서버에서는 어떤 이펙트도 실행되지 않는다.

툴팁 위치를 `useLayoutEffect` 로 잡는 컴포넌트를 SSR에 안전하게 두려면?
클라이언트 전용dynamic importssr:falseuse client
자주 하는 오해

그냥 useEffect 로 바꾸면 된다는 답. 첫 페인트에 잘못된 위치가 노출된다.