무엇
<style>는 인라인 CSS를 문서에 추가한다. React 19는 조건이 맞으면 스타일을 중복 제거하고, 우선순위대로 정렬해 <head>로 올린다.
CSS 내용은 자식으로 준다.
<style>{`p { color: red; }`}</style>
무슨 일이 일어나나
React 19의 특별 처리는 href와 precedence를 둘 다 줬을 때만 걸린다. 이때 세 가지가 일어난다.
첫째, 중복 제거. href가 같은 <style>은 여러 컴포넌트가 렌더해도 하나만 삽입된다. 둘째, hoisting. 트리 어디에 썼든 <head>로 옮겨진다. 셋째, 우선순위 정렬. precedence 값에 따라 <head> 안에서 순서가 정해진다.
precedence의 순서는 React가 트리에서 그 값을 처음 발견한 순서로 매긴다. 먼저 발견된 값이 낮은 우선순위, 나중에 발견된 값이 높은 우선순위다. 값 이름 자체("low", "high" 등)는 라벨일 뿐이고, 발견 순서가 실제 서열을 만든다. 같은 precedence끼리는 한데 묶인다(<style>이든 <link>든).
주의할 점. precedence를 쓰면 React는 href와 precedence를 뺀 나머지 prop을 버린다. 렌더 뒤 바뀐 prop은 무시되고(개발 모드 경고), 언마운트해도 스타일은 DOM에 남을 수 있다. 인라인 스타일은 로딩 중 Suspense를 띄우지 않는다.
사용법
중복 제거·정렬을 받으려면 href(고유 키)와 precedence를 함께 준다.
export function ThemeStyle() {
return (
<style href="theme-dark" precedence="medium">
{`body { background: #111; color: #eee; }`}
</style>
)
}
우선순위는 나중에 발견된 값이 이긴다. 아래에서 "high"가 "low"를 덮어쓴다.
<style href="base" precedence="low">{`p { color: gray; }`}</style>
<style href="accent" precedence="high">{`p { color: black; }`}</style>
실무 예시
props에 따라 CSS가 달라지는 컴포넌트에서, href를 그 값으로부터 만들면 같은 조합은 한 번만 삽입된다.
import { useId } from 'react'
export function PieChart({ colors }: { colors: string[] }) {
const id = useId()
const css = colors
.map((c, i) => `#${id} .color-${i} { color: ${c}; }`)
.join('\n')
return (
<>
<style href={`PieChart-${JSON.stringify(colors)}`} precedence="medium">
{css}
</style>
<svg id={id}>{/* 차트 내용 */}</svg>
</>
)
}
왜 중요한가
컴포넌트가 자기 스타일을 함께 들고 다니되, 중복 삽입과 순서 문제를 React가 정리해 주는 게 핵심이다. 같은 컴포넌트를 여러 번 렌더해도 스타일은 한 번만 들어가고, precedence로 어느 규칙이 이길지 통제할 수 있다. 다만 일상 스타일링은 대개 Tailwind나 CSS 파일, CSS Modules로 하므로 이 기능을 직접 쓸 일은 흔치 않다. 라이브러리나 동적 CSS를 다루는 특수한 경우에 유용하다.
Reference