React の `<ViewTransition>` コンポーネントで宣言的にページ遷移アニメーションを追加する
`<ViewTransition>` コンポーネントは React の実験的なバージョンとして導入されました。これは View Transition API を 宣言的な方法で使用できるようにするものです。
<ViewTransition>
コンポーネントは 2025 年 1 月現在実験的な機能です。将来にわたって API が変更される可能性があります。
React の実験的なバージョンとして <ViewTransition>
コンポーネントが導入されました。これは View Transition API を宣言的な方法で使用できるようにするものです。
View Transition API はページを遷移する際に簡単にアニメーションを追加できる API です。単一ページアプリケーション(SPA)においては document.startViewTransition()
メソッドを DOM が変更される前に呼び出すことでページ遷移アニメーションを追加できます。<ViewTransition>
コンポーネントを使用はこの API を React で使用するための方法です。
<ViewTransition>
コンポーネントを使用することでブラウザの標準的な機能を使用してページ遷移アニメーションを追加できるという利点があります。
<ViewTransition>
コンポーネントの使用
<ViewTransition>
コンポーネントは React の実験的な機能であるため、react@experimental
パッケージをインストールする必要があります。package.json
に以下のように記述します。
{
"dependencies": {
"react": "experimental",
"react-dom": "experimental"
}
}
Next.js を使用している場合には 15.2.0-canary.6
以降のバージョンが必要です。さらに next.config.js
に以下の設定を追加します。
const nextConfig = {
experimental: {
viewTransition: true,
},
}
さらに ViewTransition
は不安定な API であるため、unstable_ViewTransition
という名前で import する必要があります。
import { unstable_ViewTransition as ViewTransition } from "react";
基本的な使用方法は、以下のように条件により出し分けられるコンポーネントを <ViewTransition>
コンポーネントでラップすることです。
<ViewTransition>{condition ? <ComponentA /> : <ComponentB />}</ViewTransition>
<ViewTransition>
コンポーネントは直近の子コンポーネントに対してランダムな値で view-transition-name
CSS プロパティを追加します。View Transition API では前後の DOM ノードで同じ view-transition-name
が設定されている場合にアニメーションが適用されるます。
View Transition API によるアニメーションを適用する場合には condition
の変更を startTransition
関数でラップする必要があります。
import { useState, startTransition, unstable_ViewTransition as ViewTransition } from "react";
export function App() {
const [page, setPage] = useState("A");
const changePage = (newPage: string) => {
startTransition(() => {
setPage(newPage);
});
};
return (
<>
<button onClick={() => changePage("A")}>A</button>
<button onClick={() => changePage("B")}>B</button>
<ViewTransition>{page === "A" ? <PageA /> : <PageB />}</ViewTransition>
</>
);
}
実際に試してみると、ページ遷移時にアニメーションが適用されることがわかります。
適用するアニメーションをカスタマイズする
View Transition API はデフォルトでフェードイン/フェードアウトのアニメーションが適用されます。アニメーションをカスタマイズする場合には ::view-transition-old
, ::view-transition-new
という疑似要素を使用できます。それぞれページ遷移前の古いページ、ページ遷移後の新しいページに対して適用される疑似クラスです。
@keyframes slide-in {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
}
@keyframes slide-out {
from {
transform: translateX(0);
}
to {
transform: translateX(100%);
}
}
::view-transition-old(foo) {
animation: slide-out 0.3s ease-out;
}
::view-transition-new(foo) {
animation: slide-in 0.3s ease-out;
}
::view-transition-old
, ::view-transition-new
にはそれぞれセレクター(ここでは foo
)を指定します。このセレクターに指定する値は transition-name
と一致する必要があります。<ViewTransition>
コンポーネントをデフォルトで使用する場合にはランダムな transition-name
が設定されるためこの CSS で対象を特定できません。
<ViewTransition>
コンポーネントに name
Props を指定することで子コンポーネントに対して固定の transition-name
を設定できます。
<ViewTransition name="foo">
{page === "A" ? <PageA /> : <PageB />}
</ViewTransition>
これにより ::view-transition-old(foo)
, ::view-transition-new(foo)
が適用され、ページ遷移時にスライドアニメーションが適用されることがわかります。
<Suspense>
への適用
<ViewTransition>
コンポーネントは <Suspense>
コンポーネントと組み合わせて使用できます。<Suspense>
コンポーネントは非同期でデータを取得する際に使用されるコンポーネントです。<Suspense>
コンポーネントで非同期データの取得を行う場合には、<ViewTransition>
コンポーネントをラップすると、fallback
で指定したコンポーネントとコンテンツの遷移時にアニメーションが適用されます。
import {
Suspense,
unstable_ViewTransition as ViewTransition,
use,
} from "react";
let cache = new Map();
export function fetchData(url: string) {
if (!cache.has(url)) {
cache.set(url, getData(url));
}
return cache.get(url);
}
async function getData(url: string) {
if (url === "todos") {
return await fetchTodos();
} else {
throw Error("Not implemented");
}
}
const fetchTodos = async () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
const todos = [
{ id: 1, title: "Buy milk" },
{ id: 2, title: "Take out the trash" },
{ id: 3, title: "Wash dishes" },
];
return todos;
};
function PageA() {
const todos = use(fetchData("todos"));
return (
<div>
<h1>Page A</h1>
<ul>
{todos.map((todo: any) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
</div>
);
}
const Skelton = () => {
return <div>Loading...</div>;
};
function App() {
return (
<>
<ViewTransition>
<Suspense fallback={<Skelton />}>
<PageA />
</Suspense>
</ViewTransition>
</>
);
}
export default App;
まとめ
<ViewTransition>
コンポーネントは View Transition API を React で使用するための実験的な機能<ViewTransition>
コンポーネントでラップしたコンポーネントにランダムな値でview-transition-name
CSS プロパティが追加されるview-transition-name
の値を指定するためにはname
Props を使用する<ViewTransition>
コンポーネントは<Suspense>
コンポーネントと組み合わせて使用することができる