좋습니다. addTransitionType은 바로 직전에 배운 <ViewTransition>을 한 단계 더 세밀하게 제어하는 API입니다.
한 문장으로 먼저 잡으면:
addTransitionType은 “이번 Transition이 왜 발생했는지”에 이름표를 붙이는 API입니다.
예를 들어 둘 다 페이지 전환이지만:
뒤로 가기
앞으로 가기
검색 결과 갱신
폼 제출
은 시각적으로 다르게 처리하고 싶을 수 있습니다. 이때 Transition에 "navigation-back", "navigation-forward" 같은 원인(type)을 붙이고, <ViewTransition>이 그 type을 보고 다른 애니메이션을 선택하게 만들 수 있습니다. (React)
1. 가장 기본적인 사용법
공식 문서의 기본 패턴은 다음입니다.
import {
startTransition,
addTransitionType
} from 'react';
startTransition(() => {
addTransitionType('my-transition-type');
setState(newState);
});
중요한 구조는:
startTransition
└─ addTransitionType(...)
└─ state update
입니다.
addTransitionType을 호출하면 React는 현재 Transition에 해당 문자열을 하나의 cause, 즉 발생 원인으로 연결합니다. type에는 아무 문자열이나 사용할 수 있고, 반환값은 없습니다. (React)
2. 왜 이게 필요한가?
이전 <ViewTransition> 페이지에서 이런 코드를 봤습니다.
<ViewTransition
enter="slide-in"
exit="slide-out"
>
<Page />
</ViewTransition>
이것만으로는:
Page가 enter하면 항상 slide-in
Page가 exit하면 항상 slide-out
입니다.
그런데 navigation 방향에 따라 다르게 하고 싶다면 어떨까요?
Home → Product
= 앞으로 이동
Product → Home
= 뒤로 이동
UX를 이렇게 만들고 싶을 수 있습니다.
앞으로 이동
→ 새 화면이 오른쪽에서 왼쪽으로
뒤로 이동
→ 새 화면이 왼쪽에서 오른쪽으로
하지만 <ViewTransition> 입장에서는 둘 다 단순히:
enter
exit
일 뿐입니다.
그래서 추가 정보가 필요합니다.
이 Transition이 "forward" 때문에 일어난 건지
"back" 때문에 일어난 건지
그 정보를 붙이는 API가:
addTransitionType(...)
입니다.
3. Transition Type은 animation 종류가 아니다
이 부분을 정확히 구분해야 합니다.
addTransitionType('navigation-forward');
라고 한다고 React가 자동으로:
앞으로 슬라이드해라
라고 해석하는 게 아닙니다.
"navigation-forward"는 그냥 의미를 가진 문자열 라벨입니다.
React는:
이번 Transition의 type:
["navigation-forward"]
라고 기억합니다.
그 후 우리가 <ViewTransition>이나 CSS에서:
navigation-forward면 어떤 animation을 쓸지
정합니다.
즉:
Transition Type
= 원인/의도 정보
Animation Class
= 실제 시각 효과
입니다.
4. 실제 navigation 예제
예를 들어 간단한 router가 있다고 해봅시다.
function navigateForward(url) {
startTransition(() => {
addTransitionType('navigation-forward');
setUrl(url);
});
}
function navigateBack(url) {
startTransition(() => {
addTransitionType('navigation-back');
setUrl(url);
});
}
그러면 React 입장에서:
setUrl('/products')
라는 동일한 종류의 state update라도:
navigation-forward
인지:
navigation-back
인지 구분할 수 있습니다.
이제 <ViewTransition>이 그 차이를 활용할 수 있습니다.
5. 첫 번째 활용법: <ViewTransition> class를 type에 따라 고르기
공식 문서에서 가장 이해하기 쉬운 활용법입니다.
<ViewTransition
enter={{
'navigation-back': 'enter-right',
'navigation-forward': 'enter-left',
}}
exit={{
'navigation-back': 'exit-right',
'navigation-forward': 'exit-left',
}}
>
<Page />
</ViewTransition>
이제:
startTransition(() => {
addTransitionType('navigation-forward');
setPage(nextPage);
});
가 발생하면:
enter → enter-left
exit → exit-left
를 선택할 수 있고,
startTransition(() => {
addTransitionType('navigation-back');
setPage(previousPage);
});
이면:
enter → enter-right
exit → exit-right
가 됩니다. (React)
이 패턴이 addTransitionType의 핵심 사용 사례라고 보면 됩니다.
6. <ViewTransition>의 trigger 종류와 type은 서로 다른 축이다
직전 페이지에서 배운 것을 기억해봅시다.
ViewTransition에는:
enter
exit
update
share
layout
같은 변화 종류가 있습니다.
그리고 지금 배우는:
navigation-forward
navigation-back
submit-click
같은 것은 Transition Type입니다.
즉 두 개는 다른 질문에 답합니다.
enter / exit / update
→ UI에 "무슨 변화"가 일어났는가?
navigation-forward / back
→ "왜" 그 변화가 일어났는가?
그래서 조합할 수 있습니다.
<ViewTransition
enter={{
'navigation-forward': 'enter-from-right',
'navigation-back': 'enter-from-left',
}}
exit={{
'navigation-forward': 'exit-to-left',
'navigation-back': 'exit-to-right',
}}
>
이걸 표로 보면:
| 변화 종류 | Transition Type | animation |
|---|---|---|
| enter | navigation-forward | enter-from-right |
| exit | navigation-forward | exit-to-left |
| enter | navigation-back | enter-from-left |
| exit | navigation-back | exit-to-right |
입니다.
7. 하나의 Transition에 type을 여러 개 붙일 수도 있다
공식 문서의 중요한 caveat입니다.
startTransition(() => {
addTransitionType('navigation-forward');
addTransitionType('mobile');
setPage(nextPage);
});
처럼 하나의 Transition에 여러 type을 추가할 수 있습니다. (React)
개념적으로:
Transition Types
[
"navigation-forward",
"mobile"
]
이 됩니다.
따라서 type을 하나의 enum처럼만 생각할 필요는 없습니다.
현재 Transition에 적용되는 여러 의미적 태그
에 가깝습니다.
8. 여러 Transition이 합쳐지면 type도 합쳐진다
React는 여러 Transition을 하나로 처리할 수 있습니다.
공식 문서는 이 경우 모든 Transition Type을 수집한다고 설명합니다. (React)
예를 들어 개념적으로:
Transition A
→ "navigation"
Transition B
→ "refresh"
가 같은 작업에 합쳐지면:
["navigation", "refresh"]
처럼 둘 다 존재할 수 있습니다.
그래서 ViewTransition API에서도 type을 단일 문자열이 아니라 여러 개가 존재할 수 있는 것으로 설계합니다.
9. 여러 type이 <ViewTransition>에 동시에 match되면?
예를 들어:
<ViewTransition
enter={{
navigation: 'slide',
urgent: 'fast',
}}
>
이고 현재 Transition에:
["navigation", "urgent"]
가 모두 붙어 있다고 합시다.
공식 문서에 따르면 여러 type이 match되면 class 이름들이 합쳐집니다. (React)
즉 개념적으로:
"slide fast"
처럼 둘 다 적용됩니다.
이 때문에 type을 조합 가능한 의미 단위로 설계할 수도 있습니다.
10. 아무 type도 match하지 않는다면 default
다음처럼 작성할 수도 있습니다.
<ViewTransition
enter={{
'navigation-forward': 'enter-left',
'navigation-back': 'enter-right',
default: 'fade-in',
}}
>
현재 Transition type이:
"search-update"
인데 별도 entry가 없다면:
default → fade-in
이 사용됩니다. (React)
따라서:
특정 Transition만 특별 처리
나머지는 기본 animation
이라는 설계가 가능합니다.
11. "none"은 특별하다
예를 들어:
<ViewTransition
update={{
'background-update': 'none',
default: 'cross-fade',
}}
>
현재 Transition에:
background-update
가 포함되어 있으면 ViewTransition animation을 끌 수 있습니다.
공식 문서에서는 여러 matching type 중 하나라도 값이 "none"이면 "none"이 우선하며, 그 ViewTransition 자체가 비활성화된다고 설명합니다. (React)
즉:
type A → slide
type B → none
둘 다 현재 Transition에 존재
결과 → none
입니다.
이건 특정 종류의 업데이트에서는 애니메이션을 명시적으로 금지하고 싶을 때 유용합니다.
12. 두 번째 활용법: 브라우저 View Transition Type과 연결
조금 더 저수준 사용법입니다.
React에서:
startTransition(() => {
addTransitionType('navigation-forward');
setPage(nextPage);
});
하고 해당 Transition으로 <ViewTransition>이 활성화되면 React가 이 type을 브라우저 View Transition Type에도 연결합니다. (React)
그러면 CSS에서:
:root:active-view-transition-type(navigation-forward) {
/* 이 Transition일 때만 적용 */
}
처럼 선택할 수 있습니다.
즉 React의 의미적 정보:
navigation-forward
를 CSS 쪽에서도 알 수 있습니다.
13. 왜 ViewTransition class 방식과 browser type 방식 둘 다 있을까?
두 방식의 레벨이 다릅니다.
React <ViewTransition> class 방식
<ViewTransition
enter={{
'navigation-forward': 'enter-left'
}}
>
특정 React ViewTransition boundary가:
enter일 때
+
navigation-forward일 때
어떤 class를 받을지 결정합니다.
Browser View Transition Type 방식
:root:active-view-transition-type(navigation-forward) {
...
}
현재 전체 browser View Transition 자체의 type을 기준으로 CSS를 적용합니다.
즉:
React component 단위 제어
vs
전체 browser transition 상태 단위 제어
라는 차이가 있습니다.
일반적인 React 코드에서는 <ViewTransition> class 방식이 이해하기 더 쉽습니다.
14. 세 번째 활용법: onEnter, onUpdate 같은 이벤트
직전 페이지에서:
<ViewTransition
onUpdate={(instance) => {
...
}}
>
를 봤습니다.
addTransitionType을 사용하면 callback의 두 번째 인자로 type 목록도 받을 수 있습니다.
공식 문서 예시는:
<ViewTransition
onUpdate={(inst, types) => {
if (types.includes('navigation-back')) {
// back animation
} else if (types.includes('navigation-forward')) {
// forward animation
} else {
// default
}
}}
>
형태입니다. (React)
즉 imperative animation을 쓸 때도:
왜 이 Transition이 발생했는가?
를 확인할 수 있습니다.
15. CSS보다 JS animation이 필요한 경우
예를 들어:
<ViewTransition
onEnter={(instance, types) => {
if (types.includes('navigation-forward')) {
const animation = instance.new.animate(
[
{ transform: 'translateX(100%)' },
{ transform: 'translateX(0)' },
],
{ duration: 300 }
);
return () => animation.cancel();
}
}}
>
같이 만들 수 있습니다.
여기서:
types
= Transition의 원인
instance
= View Transition snapshot 조작 대상
이라고 보면 됩니다.
따라서 addTransitionType 자체가 animation을 실행하는 게 아니라 animation 선택에 필요한 context를 전달하는 역할입니다.
16. addTransitionType은 어디서 호출해야 하나?
공식 문서의 기본 사용법은:
startTransition(() => {
addTransitionType('submit-click');
action();
});
입니다. (React)
즉 핵심은:
Transition scope 안에서 호출해야 한다.
입니다.
이런 구조로 기억하세요.
function handleForward() {
startTransition(() => {
addTransitionType('navigation-forward');
navigate('/next');
});
}
Transition의 원인을 붙이는 API이므로 Transition과 별개로 임의의 render에서 호출하는 식으로 사용하지 않습니다.
17. startTransition과 역할을 구분하자
이 둘은 자주 같이 보이기 때문에 헷갈릴 수 있습니다.
startTransition(() => {
addTransitionType('navigation-forward');
setPage(nextPage);
});
여기서:
startTransition
이 state update는 Transition이다.
라는 스케줄링 의미를 제공합니다.
addTransitionType
그리고 이 Transition의 원인은 navigation-forward다.
라는 의미적 metadata를 제공합니다.
즉:
startTransition
= 업데이트의 처리 방식
addTransitionType
= 업데이트의 원인 라벨
입니다.
18. addTransitionType과 <ViewTransition>도 역할이 다르다
마찬가지입니다.
addTransitionType
→ "왜" 변화했는지 표시
<ViewTransition>
→ "어디를 어떻게 animate할지" 정의
따라서 보통 흐름은:
사용자 행동
↓
startTransition
↓
addTransitionType("navigation-forward")
↓
state 변경
↓
React 렌더링
↓
<ViewTransition> 변화 감지
↓
현재 type 확인
↓
적절한 animation 선택
입니다.
19. 중요한 caveat: type은 commit마다 reset된다
이 페이지에서 가장 놓치기 쉬운 내용입니다.
공식 문서는:
Transition Types는 각 commit 이후 reset된다.
고 설명합니다. (React)
이게 무슨 뜻인지 Suspense로 보겠습니다.
startTransition(() => {
addTransitionType('navigation-forward');
setPage(<SlowPage />);
});
SlowPage가 suspend한다고 해봅시다.
첫 번째 commit:
기존 UI
→ Suspense fallback
이 commit은 startTransition과 직접 연결되어 있기 때문에:
navigation-forward
type이 있습니다.
하지만 나중에 데이터가 준비돼서:
fallback
→ 실제 SlowPage
로 reveal되는 건 별도의 commit입니다.
이때는 이전 type이 자동으로 이어지지 않습니다. (React)
20. Suspense와 연결해서 정확히 이해해보자
흐름을 보면:
startTransition
addTransitionType("navigation-forward")
setPage()
│
▼
SlowPage suspend
│
▼
Commit #1
fallback 표시
type = navigation-forward ✅
...데이터 기다림...
Commit #2
실제 콘텐츠 reveal
type = 없음 ❌
입니다.
즉 Transition Type은:
어떤 비동기 작업의 전체 수명 동안 유지되는 global context
가 아닙니다.
각 commit에서 적용되는 metadata입니다.
이건 꽤 중요한 차이입니다.
21. 왜 이렇게 설계됐을까?
보충 설명
addTransitionType은:
"이 Promise와 관련된 모든 향후 UI 업데이트는 forward다"
라는 의미가 아니라,
"현재 Transition으로 발생시키고 있는 이 UI 변경의 원인은 forward다"
에 가깝습니다.
Suspense reveal은 시간이 지난 뒤 다른 상황에서 별도의 React commit으로 일어날 수 있으므로 원래 type을 무조건 유지하면 오히려 잘못된 animation이 적용될 수 있습니다.
그래서 commit 단위로 reset되는 것으로 이해하면 자연스럽습니다.
22. 실제 router를 설계한다면
가장 대표적인 패턴을 만들어봅시다.
function Router() {
const [page, setPage] = useState('/');
function push(url) {
startTransition(() => {
addTransitionType('navigation-forward');
setPage(url);
});
}
function back(url) {
startTransition(() => {
addTransitionType('navigation-back');
setPage(url);
});
}
return (
<ViewTransition
enter={{
'navigation-forward': 'page-enter-from-right',
'navigation-back': 'page-enter-from-left',
}}
exit={{
'navigation-forward': 'page-exit-to-left',
'navigation-back': 'page-exit-to-right',
}}
>
<Page route={page} />
</ViewTransition>
);
}
여기서 architecture를 보면:
Router
→ navigation 의미를 안다
→ addTransitionType 호출
ViewTransition
→ 시각적 표현을 안다
→ type별 animation 선택
으로 역할이 깔끔하게 나뉩니다.
23. 이 분리가 좋은 이유
Router 같은 로직에서는:
addTransitionType('navigation-forward');
만 알려줍니다.
Router가:
300ms
translateX(100%)
ease-out
같은 시각 정보를 알 필요가 없습니다.
반대로 <ViewTransition>에서는:
navigation-forward
→ slide-left
만 결정합니다.
즉:
도메인/행동 의미
navigation-forward
↓
시각적 표현
slide-left
을 분리할 수 있습니다.
이게 addTransitionType의 좋은 설계 포인트입니다.
24. 폼 제출에도 사용할 수 있다
공식 문서도:
addTransitionType('submit-click');
예제를 사용합니다. (React)
예를 들어:
function handleSubmit() {
startTransition(() => {
addTransitionType('form-submit');
submitAction();
});
}
그리고:
<ViewTransition
update={{
'form-submit': 'submit-transition',
default: 'regular-update',
}}
>
<FormResult />
</ViewTransition>
처럼 할 수 있습니다.
따라서 Transition Type은 navigation 전용이 아닙니다.
navigation-forward
navigation-back
form-submit
filter-change
search
sort-change
처럼 앱의 의미에 맞춰 자유롭게 만들 수 있습니다.
25. 이름은 구현이 아니라 “원인” 중심이 좋다
보충 설명
이 API의 이름 자체가:
specify the cause of a transition
입니다.
따라서 이런 이름:
addTransitionType('slide-left');
보다는:
addTransitionType('navigation-forward');
가 더 좋은 모델인 경우가 많습니다.
왜냐하면:
navigation-forward
라는 의미는 유지하면서 디자인을 나중에:
slide-left
→ fade
→ zoom
로 자유롭게 바꿀 수 있기 때문입니다.
즉:
❌ animation 이름
addTransitionType("slide-left")
✅ 사용자 행동/원인
addTransitionType("navigation-forward")
처럼 separation of concerns를 가져갈 수 있습니다.
26. 여러 type을 조합한다면 역시 의미 중심으로
예를 들어:
startTransition(() => {
addTransitionType('navigation-forward');
addTransitionType('modal');
setRoute(nextRoute);
});
처럼 만들 수 있습니다.
그러면 ViewTransition 쪽에서:
navigation-forward
→ 이동 방향 결정
modal
→ modal 특화 animation 추가
처럼 조합할 수 있습니다.
다만 type이 많아지면 interaction 설계가 복잡해지므로 “CSS class를 전달하는 우회 수단”처럼 남용하는 것은 피하는 편이 좋습니다.
27. addTransitionType은 현재 주로 ViewTransition용이다
공식 문서에서는 현재 Transition Type을 사용할 수 있는 주된 용도가 Transition의 원인에 따라 View Transition animation을 다르게 하는 것이라고 설명합니다.
그리고 향후 더 많은 사용처를 지원할 계획이라고 명시합니다. (React)
따라서 지금은 mental model을:
Transition에 metadata 추가
→ 현재 주요 소비자는 ViewTransition
이라고 잡으면 됩니다.
28. 지금까지의 API를 한꺼번에 연결
최근 배운 API를 한 흐름으로 보겠습니다.
사용자가 상품 목록에서 상품을 클릭합니다.
사용자 클릭
↓
startTransition(...)
React에게:
이건 non-urgent Transition이다
라고 알려줍니다.
그 안에서:
addTransitionType('navigation-forward');
를 호출합니다.
React에게:
이 Transition이 발생한 이유는
앞으로 navigation했기 때문이다
라고 알려줍니다.
state를 변경합니다.
setPage('product-detail');
새 화면 일부가 아직 준비 안 됐다면:
Suspense
→ loading/reveal 조율
합니다.
그리고 UI 변화가 <ViewTransition> 안에서 발생하면:
ViewTransition
→ enter / exit / update / share 확인
→ Transition Type 확인
→ 적절한 animation 선택
합니다.
전체 그림:
사용자 행동
│
▼
startTransition
"이 update는 Transition"
│
▼
addTransitionType
"원인은 navigation-forward"
│
▼
setState
│
▼
React render
│
├── Suspense
│ 준비 상태 조율
│
▼
commit
│
▼
ViewTransition
├── 변화 종류: enter/exit/update/share
└── 원인: navigation-forward
│
▼
animation 선택
이 흐름을 이해하면 addTransitionType은 어려운 API가 아닙니다.
핵심 정리
addTransitionType을 한 문장으로 설명하면:
현재 React Transition에 “왜 이 Transition이 발생했는지”를 나타내는 문자열 type을 추가하는 API입니다. (React)
기본 패턴은:
startTransition(() => {
addTransitionType('navigation-forward');
setState(newState);
});
입니다.
특히 다음을 기억하세요.
- type은 아무 문자열이나 사용할 수 있고 반환값은 없습니다.
- 하나의 Transition에 여러 type을 추가할 수 있습니다.
- 여러 Transition이 합쳐지면 그 type들도 함께 수집됩니다. (React)
- 현재 주요 용도는
<ViewTransition>animation을 Transition이 발생한 원인에 따라 다르게 선택하는 것입니다. <ViewTransition>의enter/exit/update/share는 무슨 UI 변화가 일어났는지, Transition Type은 왜 그 변화가 일어났는지를 나타냅니다.- type에 따른 View Transition Class, 브라우저 View Transition Type CSS,
onEnter/onUpdate등의 JS event 세 방식으로 활용할 수 있습니다. (React) - Transition Type은 commit마다 reset됩니다. 따라서 Suspense fallback commit에는 type이 있을 수 있지만 나중의 content reveal commit까지 자동으로 유지되지는 않습니다. (React)
이해도 테스트
정답은 바로 알려주지 않겠습니다.
- 다음 코드에서
startTransition과addTransitionType의 역할 차이를 각각 설명해보세요.
startTransition(() => {
addTransitionType('navigation-forward');
setPage(nextPage);
});
<ViewTransition>의enter와"navigation-forward"라는 Transition Type은 어떤 점에서 서로 다른 정보를 나타낼까요?다음처럼 한 Transition에 type을 두 개 추가하면 React는 어떻게 처리할까요?
startTransition(() => {
addTransitionType('navigation-forward');
addTransitionType('modal');
setState(nextState);
});
addTransitionType('slide-left')보다addTransitionType('navigation-forward')같은 이름이 일반적으로 더 좋은 이유는 무엇일까요?navigation-forwardtype이 붙은 Transition에서 Suspense fallback이 먼저 commit되고 실제 콘텐츠는 나중에 reveal된다면, 실제 콘텐츠가 reveal되는 commit에도 자동으로navigation-forward가 남아 있을까요?
'리액트 > 레퍼런스 (react 19ver)' 카테고리의 다른 글
| cacheSignal (0) | 2026.09.15 |
|---|---|
| cache (0) | 2026.09.15 |
| act (0) | 2026.09.15 |
| <ViewTransition> (0) | 2026.09.15 |
| <Activity> (0) | 2026.09.14 |