useInsertionEffect

김동현·2026년 3월 17일

useInsertionEffect

⚠️ 주의

useInsertionEffect는 CSS-in-JS 라이브러리 제작자를 위한 Hook이에요. CSS-in-JS 라이브러리를 만들고 있고 스타일을 주입할 위치가 필요한 경우가 아니라면, 아마 useEffectuseLayoutEffect를 대신 사용하고 싶을 거예요.

소개

useInsertionEffect는 어떤 레이아웃 Effect가 실행되기 전에 DOM에 요소를 삽입할 수 있게 해줘요.

useInsertionEffect(setup, dependencies?)

목차


레퍼런스 {/reference/}

useInsertionEffect(setup, dependencies?) {/useinsertioneffect/}

레이아웃을 읽어야 할 수도 있는 Effect가 실행되기 전에 스타일을 삽입하려면 useInsertionEffect를 호출하세요:

import { useInsertionEffect } from 'react';

// Inside your CSS-in-JS library
function useCSS(rule) {
  useInsertionEffect(() => {
    // ... inject <style> tags here ...
  });
  return rule;
}

아래에서 더 많은 예시를 확인하세요.

매개변수 {/parameters/}

  • setup: Effect의 로직이 담긴 함수예요. setup 함수는 선택적으로 클린업(cleanup) 함수를 반환할 수도 있어요. 컴포넌트가 DOM에 추가될 때, 하지만 어떤 레이아웃 Effect가 실행되기 전에, React가 setup 함수를 실행해요. 의존성이 변경된 매 리렌더링 후에, React는 먼저 이전 값으로 클린업 함수를 실행하고(제공했다면), 그 다음 새로운 값으로 setup 함수를 실행해요. 컴포넌트가 DOM에서 제거되면, React가 클린업 함수를 실행해요.

  • 선택적 dependencies: setup 코드 안에서 참조하는 모든 반응형 값들의 목록이에요. 반응형 값에는 props, state, 그리고 컴포넌트 본문 안에서 직접 선언된 모든 변수와 함수가 포함돼요. 린터가 React용으로 설정되어 있다면, 모든 반응형 값이 의존성으로 올바르게 지정되었는지 검증해줄 거예요. 의존성 목록은 항목 수가 일정해야 하고, [dep1, dep2, dep3]처럼 인라인으로 작성해야 해요. React는 각 의존성을 이전 값과 Object.is 비교 알고리즘을 사용해서 비교해요. 의존성을 아예 지정하지 않으면, 컴포넌트의 매 리렌더링마다 Effect가 다시 실행돼요.

반환값 {/returns/}

useInsertionEffectundefined를 반환해요.

주의사항 {/caveats/}

  • Effect는 클라이언트에서만 실행돼요. 서버 렌더링 중에는 실행되지 않아요.
  • useInsertionEffect 안에서는 state를 업데이트할 수 없어요.
  • useInsertionEffect가 실행되는 시점에는 ref가 아직 연결되지 않은 상태예요.
  • useInsertionEffect는 DOM이 업데이트되기 전에 실행될 수도 있고 후에 실행될 수도 있어요. 특정 시점에 DOM이 업데이트되어 있을 거라고 기대하면 안 돼요.
  • 다른 종류의 Effect들은 모든 Effect의 클린업을 먼저 실행하고 나서 모든 Effect의 setup을 실행하는 반면, useInsertionEffect는 컴포넌트 하나씩 클린업과 setup을 모두 실행해요. 이 때문에 클린업과 setup 함수가 "인터리빙(interleaving, 교차 실행)"되는 결과가 생겨요.

💡 부연설명: "인터리빙"이라는 게 무슨 뜻이냐면, 일반적인 useEffect의 경우 컴포넌트 A의 클린업 → 컴포넌트 B의 클린업 → 컴포넌트 A의 setup → 컴포넌트 B의 setup 순으로 실행되는데요, useInsertionEffect는 컴포넌트 A의 클린업 → 컴포넌트 A의 setup → 컴포넌트 B의 클린업 → 컴포넌트 B의 setup 이런 식으로 한 컴포넌트의 클린업과 setup이 연달아 실행된다는 뜻이에요.


사용법 {/usage/}

CSS-in-JS 라이브러리에서 동적 스타일 주입하기 {/injecting-dynamic-styles-from-css-in-js-libraries/}

전통적으로는 일반 CSS를 사용해서 React 컴포넌트에 스타일을 적용했어요.

// In your JS file:
<button className="success" />

// In your CSS file:
.success { color: green; }

어떤 팀들은 CSS 파일을 작성하는 대신 JavaScript 코드 안에서 직접 스타일을 작성하는 것을 선호해요. 이런 방식은 보통 CSS-in-JS 라이브러리나 도구를 사용해야 해요. CSS-in-JS에는 세 가지 일반적인 접근 방식이 있어요:

  1. 컴파일러를 사용한 CSS 파일로의 정적 추출
  2. 인라인 스타일, 예: <div style={{ opacity: 1 }}>
  3. <style> 태그의 런타임 주입

CSS-in-JS를 사용한다면, 처음 두 가지 접근 방식의 조합을 추천해요 (정적 스타일은 CSS 파일, 동적 스타일은 인라인 스타일). 런타임 <style> 태그 주입은 두 가지 이유로 추천하지 않아요:

  1. 런타임 주입은 브라우저가 스타일을 훨씬 더 자주 다시 계산하도록 강제해요.
  2. 런타임 주입은 React 라이프사이클에서 잘못된 시점에 발생하면 매우 느릴 수 있어요.

첫 번째 문제는 해결할 수 없지만, useInsertionEffect는 두 번째 문제를 해결하는 데 도움이 돼요.

어떤 레이아웃 Effect가 실행되기 전에 스타일을 삽입하려면 useInsertionEffect를 호출하세요:

// Inside your CSS-in-JS library
let isInserted = new Set();
function useCSS(rule) {
  useInsertionEffect(() => {
    // As explained earlier, we don't recommend runtime injection of <style> tags.
    // But if you have to do it, then it's important to do in useInsertionEffect.
    if (!isInserted.has(rule)) {
      isInserted.add(rule);
      document.head.appendChild(getStyleForRule(rule));
    }
  });
  return rule;
}

function Button() {
  const className = useCSS('...');
  return <div className={className} />;
}

useEffect와 마찬가지로, useInsertionEffect는 서버에서는 실행되지 않아요. 서버에서 어떤 CSS 규칙이 사용되었는지 수집해야 한다면, 렌더링 중에 할 수 있어요:

let collectedRulesSet = new Set();

function useCSS(rule) {
  if (typeof window === 'undefined') {
    collectedRulesSet.add(rule);
  }
  useInsertionEffect(() => {
    // ...
  });
  return rule;
}

런타임 주입을 사용하는 CSS-in-JS 라이브러리를 useInsertionEffect로 업그레이드하는 방법에 대해 더 읽어보세요.

이게 렌더링 중이나 useLayoutEffect에서 스타일을 주입하는 것보다 왜 더 나을까요? {/how-is-this-better-than-injecting-styles-during-rendering-or-uselayouteffect/}

렌더링 중에 스타일을 삽입하고 React가 논블로킹 업데이트를 처리하고 있다면, 브라우저가 컴포넌트 트리를 렌더링하는 동안 매 프레임마다 스타일을 다시 계산하게 되는데, 이건 엄청나게 느릴 수 있어요.

useInsertionEffectuseLayoutEffectuseEffect 중에 스타일을 삽입하는 것보다 더 나은데, 왜냐하면 컴포넌트에서 다른 Effect들이 실행될 때쯤이면 <style> 태그가 이미 삽입되어 있는 것을 보장하기 때문이에요. 그렇지 않으면, 일반 Effect에서의 레이아웃 계산이 오래된 스타일 때문에 잘못될 수 있어요.

💡 부연설명: 쉽게 정리하자면, Effect들의 실행 순서는 useInsertionEffectuseLayoutEffectuseEffect 순서예요. 그래서 useInsertionEffect에서 <style> 태그를 삽입하면, 이후에 실행되는 useLayoutEffect에서 레이아웃을 측정할 때 이미 최신 스타일이 적용된 상태에서 올바른 값을 읽을 수 있는 거예요. 만약 useLayoutEffect에서 스타일을 주입하면, 같은 시점에 실행되는 다른 useLayoutEffect가 아직 적용되지 않은 스타일로 레이아웃을 계산할 수도 있어서 문제가 생길 수 있죠. 이게 바로 useInsertionEffect가 존재하는 이유예요!

profile
프론트에_가까운_풀스택_개발자

0개의 댓글