2025年4月23日 by Ricky Hanlon
React Labsの投稿では、活発な研究開発中のプロジェクトについて書いています。この投稿では、今日から試すことができる2つの新しい実験的機能と、現在取り組んでいる他の分野のアップデートを共有します。
本日、テスト準備が整った2つの新しい実験的機能のドキュメントをリリースできることを嬉しく思います:
- View Transitions
- Activity
また、現在開発中の新機能についてもアップデートを共有します:
- React Performance Tracks
- Compiler IDE Extension
- Automatic Effect Dependencies
- Fragment Refs
- Concurrent Stores
新しい実験的機能
注意 <Activity /> は react@19.2 で出荷されました。<ViewTransition /> と addTransitionType は react@canary で利用可能になりました。
View Transitions と Activity は react@experimental でテスト準備が整いました。これらの機能は本番環境でテストされており安定していますが、フィードバックを取り入れる過程で最終的なAPIは変更される可能性があります。
Reactパッケージを最新の実験版にアップグレードすることで試すことができます:
- react@experimental
- react-dom@experimental
アプリでこれらの機能を使用する方法について読み進めるか、新しく公開されたドキュメントをチェックしてください:
<ViewTransition>:Transitionのアニメーションを有効にするコンポーネント
- addTransitionType:Transitionの原因を指定できる関数
<Activity>:UIの一部を隠したり表示したりできるコンポーネント
View Transitions
React View Transitionsは、アプリのUIトランジションにアニメーションを追加しやすくする新しい実験的機能です。内部的には、これらのアニメーションは最新のブラウザで利用可能な新しいstartViewTransition APIを使用します。
要素のアニメーションをオプトインするには、新しい<ViewTransition>コンポーネントでラップします:
<ViewTransition>
<div>animate me</div>
</ViewTransition>
この新しいコンポーネントを使用すると、アニメーションが有効になったときに"何を"アニメーションするかを宣言的に定義できます。View Transitionの3つのトリガーのいずれかを使用して"いつ"アニメーションするかを定義できます:
startTransition(() => setState(...));
const deferred = useDeferredValue(value);
<Suspense fallback={<Fallback />}>
<div>Loading...</div>
</Suspense>
デフォルトでは、これらのアニメーションはView Transitionsに適用されるデフォルトのCSSアニメーション(通常はスムーズなクロスフェード)を使用します。view transition疑似セレクターを使用して、アニメーションの"方法"を定義できます。例えば、*を使用してすべてのトランジションのデフォルトアニメーションを変更できます:
::view-transition-old(*) {
animation: 300ms ease-out fade-out;
}
::view-transition-new(*) {
animation: 300ms ease-in fade-in;
}
startTransition、useDeferredValue、またはSuspenseフォールバックがコンテンツに切り替わるなどのアニメーショントリガーによってDOMが更新されると、Reactは宣言的ヒューリスティックを使用して、アニメーション用に有効にする<ViewTransition>コンポーネントを自動的に決定します。その後、ブラウザはCSSで定義されたアニメーションを実行します。
ブラウザのView Transition APIに精通していて、Reactがそれをどのようにサポートするかを知りたい場合は、ドキュメントの「How does <ViewTransition> Work」をチェックしてください。
この投稿では、View Transitionsの使用方法のいくつかの例を見てみましょう。以下のインタラクションをアニメーションしないこのアプリから始めます:
- ビデオをクリックして詳細を表示
- "back"をクリックしてフィードに戻る
- リストに入力してビデオをフィルタリング
注意 View TransitionsはCSSとJSドリブンアニメーションを置き換えるものではありません
View Transitionsは、ナビゲーション、展開、開閉、並び替えなどのUIトランジションに使用することを意図しています。アプリのすべてのアニメーションを置き換えることを意図していません。上記のサンプルアプリでは、"like"ボタンをクリックしたときやSuspenseフォールバックのグリマーに既にアニメーションがあることに注意してください。これらは特定の要素をアニメーションしているため、CSSアニメーションの良いユースケースです。
ナビゲーションのアニメーション
私たちのアプリには、ページトランジションが既にTransitionsとしてマークされたSuspense対応ルーターが含まれています。つまり、ナビゲーションはstartTransitionで実行されます:
function navigate(url) {
startTransition(() => {
go(url);
});
}
startTransitionはView Transitionトリガーなので、<ViewTransition>を追加してページ間をアニメーションできます:
<ViewTransition key={url}>
{url === '/' ? <Home /> : <TalkDetails />}
</ViewTransition>
urlが変更されると、<ViewTransition>と新しいルートがレンダリングされます。<ViewTransition>がstartTransition内で更新されたため、<ViewTransition>がアニメーション用に有効になります。
デフォルトでは、View Transitionsにはブラウザのデフォルトクロスフェードアニメーションが含まれます。これを例に追加すると、ページ間をナビゲートするたびにクロスフェードが発生します:
import { ViewTransition } from 'react';
import Details from './Details';
import Home from './Home';
import { useRouter } from './router';
export default function App() {
const { url } = useRouter();
return (
<ViewTransition>
{url === '/' ? <Home /> : <Details />}
</ViewTransition>
);
}
私たちのルーターは既にstartTransitionを使用してルートを更新しているため、<ViewTransition>を追加するこの1行の変更で、デフォルトのクロスフェードアニメーションが有効になります。
注意 <ViewTransition>アニメーションのオプトアウト
この例では、簡単にするためにアプリのルートを<ViewTransition>でラップしていますが、これはアプリのすべてのトランジションがアニメーションされることを意味し、予期しないアニメーションにつながる可能性があります。修正するために、各ページが独自のアニメーションを制御できるように、ルートの子を"none"でラップしています:
<ViewTransition default="none">
{children}
</ViewTransition>
実際には、ナビゲーションは"enter"と"exit"プロップを使用するか、Transition Typesを使用して行う必要があります。
アニメーションのカスタマイズ
デフォルトでは、<ViewTransition>にはブラウザからのデフォルトクロスフェードが含まれます。アニメーションをカスタマイズするには、<ViewTransition>コンポーネントにプロップを提供して、<ViewTransition>の有効化方法に基づいて使用するアニメーションを指定できます。
例えば、デフォルトのクロスフェードアニメーションを遅くできます:
<ViewTransition default="slow-fade">
<Home />
</ViewTransition>
そして、view transition classesを使用してCSSでslow-fadeを定義します:
::view-transition-old(.slow-fade) {
animation-duration: 500ms;
}
::view-transition-new(.slow-fade) {
animation-duration: 500ms;
}
これで、クロスフェードが遅くなります。
詳細については、<ViewTransition>のスタイリングの完全ガイドである「Styling View Transitions」を参照してください。
共有要素トランジション
2つのページに同じ要素が含まれている場合、多くの場合、あるページから次のページにアニメーションしたいと思うでしょう。これを行うには、<ViewTransition>に一意の名前を追加できます:
<ViewTransition name={`video-${video.id}`}>
<Thumbnail video={video} />
</ViewTransition>
これで、ビデオサムネイルが2つのページ間でアニメーションします。
デフォルトでは、Reactはトランジション用に有効化された各要素に対して一意の名前を自動的に生成します(「How does <ViewTransition> work」を参照)。Reactが名前付きの<ViewTransition>が削除され、同じ名前の新しい<ViewTransition>が追加されるトランジションを検出すると、共有要素トランジションを有効にします。
詳細については、「Animating a Shared Element」のドキュメントを参照してください。
原因に基づくアニメーション
時には、トリガーされた方法に基づいて要素を異なってアニメーションしたい場合があります。このユースケースのために、トランジションの原因を指定するaddTransitionTypeという新しいAPIを追加しました:
function navigate(url) {
startTransition(() => {
addTransitionType('nav-forward');
go(url);
});
}
function navigateBack(url) {
startTransition(() => {
addTransitionType('nav-back');
go(url);
});
}
トランジションタイプを使用すると、<ViewTransition>のプロップを介してカスタムアニメーションを提供できます。"6 Videos"と"Back"のヘッダーに共有要素トランジションを追加しましょう:
<ViewTransition
name="nav"
share={{
'nav-forward': 'slide-forward',
'nav-back': 'slide-back',
}}
>
{heading}
</ViewTransition>
ここでは、トランジションタイプに基づいてアニメーション方法を定義するshareプロップを渡します。nav-forwardから共有トランジションが有効になると、view transition classのslide-forwardが適用されます。nav-backからの場合、slide-backアニメーションが有効になります。
これらのアニメーションをCSSで定義しましょう:
::view-transition-old(.slide-forward) {