함정
useInsertionEffect는 CSS-in-JS 라이브러리 저자들을 위한 훅이에요. CSS-in-JS 라이브러리로 작업하지 않거나, 스타일을 주입할 공간이 필요하지 않으면 아마도 useEffect나 useLayoutEffect를 사용하는 게 좋아요.
useInsertionEffect
는 어떤 레이아웃 이펙트가 실행되기 이전에 DOM에 엘리먼트를 추가해줘요.
useInsertionEffect(setup, depencies?)
Reference | 레퍼런스
useInsertionEffect(setup, dependencies?)
레이아웃을 읽는 이펙트가 실행되기 전에 스타일을 삽입하려면 useInsertionEffect
를 호출하세요.
import { useInsertionEffect } from 'react';
// CSS-in-JS 라이브러리 내부에서
function useCSS(rule) {
useInsertionEffect(() => {
// ... <style> 태그를 이곳에 삽입하세요.
});
return rule;
}
Parameters | 파라미터(매개변수)
setup
: 이펙트의 로직을 가진 함수. setup 함수는 선택적으로 cleanup 함수를 반환할 수도 있어요. 어떤 레이아웃 이펙트가 실행되기 전에 컴포넌트가 DOM에 추가되면 리액트는 setup 함수를 실행할 거예요. 변화된 의존성으로 인한 모든 리렌더링 후에 리액트는 (값을 제공받았따면) 옛날 값으로 cleanup 함수를 먼저 실행하고, 그 다음에 새 값을 setup 함수를 실행해요. 컴포넌트가 DOM 에서 제거되면 리액트는 clenaup 함수를 실행해요.dependencies
(선택적) :setup
코드의 내부에서 참조하는 반응값의 목록. 반응값은 props, 상태, 그리고 컴포넌트 바디 내부에서 선언된 모든 변수와 함수를 포함해요. 만약 린터가 리액트에 맞게 구성되어 있다면, 모든 반응 값이 올바르게 의존성으로 지정되어 있는지를 확인해요. 의존성 목록은 일정한 숫자의 아이템을 가지고 있어야하고[dep1, dep2, dep3]
과 같이 인라인으로 작성해야해요. 리액트는 각 의존성을Object.js
의 비교 알고리즘을 사용하여 이전의 값과 비교해요. 만약 이 인자를 생략한다면 해당 이펙트는 컴포넌트의 모든 리렌더링 후에 재실행 될거예요.
Returns | 반환값
useInsertionEffect
는 undefined
를 반환해요.
Caveats | 주의사항
- 이펙트는 클라이언트 사이드에서만 동작해요. 서버 렌더링 동안에는 실행할 수 없어요.
useInsertoinEffect
내부에서 상태를 업데이트할 수 없어요.useIntsertionEffect
가 실행될 때에 ref는 아직 연결되지 않았어요.useInsertionEffect
는 DOM이 업데이트 되기 전 또는 된 후 모두에서 실행할 수 있어요. 특정 시간에 업데이트되는 DOM에 의존하지 마세요.- 모든 이펙트에 대한 클린업 함수를 실행하고나서 모든 이펙트에 대한 셋업을 실행하는 다른 Effects와는 달리
uuseInsertionEffect
는 한 컴포넌트에 대한 cleanup과 setup 함수를 한번에 실행해요. 이로 인해 cleanup과 setup 함수가 "끼워넣어"져요.
Usage | 용법
Intecting dynamic styles from CSS-in-JS libraries | CSS-in-JS 라이브러리에서 동적 스타일 삽입하기
전통적으로 리액트 컴포넌트는 플레인 CSS를 사용해요.
// JS 파일에서:
<button className="success" />
/* CSS 파일에서: */
.success { color: green; }
몇몇 팀은 CSS 파일을 작성하는 것보다 자바스크립트 코드로 직접 스타일을 작성하는 것을 선호해요. 이는 보통 CSS-in-JS 라이브러리나 다른 도구를 사용해야해요. CSS-in-JS를 사용하는 방법에는 세 가지가 있어요.:
- 컴파일러로 CSS 파일을 정적 추출하기
<div style={{ opacity : 1 }}
과 같은 인라인 스타일 사용하기<style>
태그를 런타임에 삽입하기
만약 CSS-in-JS를 사용한다면 1번과 2번 (컴파일러로 CSS 파일 정적 추출하기, <div style={{ opacity : 1 }}
과 같은 인라인 스타일 사용하기) 방법을 섞어서 사용하기를 추천해요. <style>
태그를 런타임에 삽입하는 것은 두가지 이유로 추천하지 않아요.
- 런타임 삽입은 브라우저가 스타일을 너무 자주 계산하게 만들어요.
- 런타임 삽입은 리액트 라이프사이클에서 잘못된 때에 발생한다면 굉장히 느릴 수 있어요.
첫번제 문제는 해결할 수 없지만 useInsertionEffect
는 두번째 문제를 해결하는데 도움이 되어요.
레이아웃 이펙트가 실행되기 전에 스타일을 삽입하려면 useInsertionEffect
를 호출하세요.
// CSS-in-JS 라이브러리 내부에서
let isInserted = new Set();
function useCSS(rule) {
useInsertionEffect(() => {
// 위에 설명했던 대로 <style> 태그의 런타임 삽입은 추천하지 않아요.
// 그러나 해당 방법을 사용해야한다면 useInsertion안에서 실행하는 것이 중요해요.
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 동안 스타일을 삽입하는 것보다 이 방법이 왜 더 나을까요?
만약 렌더링하는 동안 스타일을 추가하고 싶고 리액트가 논 블로킹 업데이트를 실행하고 있다면 브라우저는 컴포넌트를 렌더링 하는 동안 모든 프레임을 각각 재계산할 것이고 이는 굉장히 느려요.
useInsertionEffect
는 useEffect
나 useLayoutEffect
이 실행되는 동안 스타일을 삽입하는 것보다 나아요. 왜냐하면 useInsertionEffect
는 다른 이펙트가 컴포넌트 안에서 실행될 때, <style>
태그가 이미 삽입되었다는 것을 보장하기 때문이에요. 하지만 보통 이펙트에서의 레이아웃 계산은 오래된 스타일 때문에 레이아웃이 잘못 계산될 수 있어요.
'리액트 공식문서 | React Docs > Reference > react@18.2.0' 카테고리의 다른 글
[Hooks] useMemo | useMemo 훅 (0) | 2024.02.01 |
---|---|
[Hooks] useLayoutEffect | useLayoutEffect 훅 (1) | 2024.01.25 |
[Hooks] useImperativeHandle | useImperativeHandle훅 (1) | 2024.01.21 |
[Hooks] useId | useId 훅 (0) | 2024.01.21 |
[Hooks] useEffect | useEffect 훅 (0) | 2024.01.18 |