tanstack-query
TypeScript/JavaScriptおよびReact、Vue、Solid、Svelte、Angularに対応した、強力な非同期状態管理・サーバーステート操作・データフェッチングライブラリです。サーバーから取得するデータのキャッシュや同期、更新を効率的に扱いたい場合に活用できます。
description の原文を見る
Powerful asynchronous state management, server-state utilities, and data fetching for TS/JS, React, Vue, Solid, Svelte & Angular.
SKILL.md 本文
概要
TanStack Query (旧 React Query) はサーバーステート(サーバーに存在し、フェッチ、キャッシュ、同期、更新が必要なデータ)を管理します。自動キャッシング、バックグラウンドリフェッチ、stale-while-revalidateパターン、ページネーション、無限スクロール、楽観的更新がそのまま利用できます。
パッケージ: @tanstack/react-query
Devtools: @tanstack/react-query-devtools
現在のバージョン: v5
インストール
npm install @tanstack/react-query
npm install -D @tanstack/react-query-devtools # オプション
セットアップ
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60, // 1分
gcTime: 1000 * 60 * 5, // 5分 (ガベージコレクション)
retry: 3,
refetchOnWindowFocus: true,
refetchOnReconnect: true,
},
},
})
function App() {
return (
<QueryClientProvider client={queryClient}>
<YourApp />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
)
}
コアコンセプト
クエリキー
クエリキーはキャッシュされたデータを一意に識別します。シリアライズ可能な配列である必要があります:
// シンプルなキー
useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
// 変数付き(依存配列パターン)
useQuery({ queryKey: ['todos', { status, page }], queryFn: fetchTodos })
// 無効化用の階層的キー
useQuery({ queryKey: ['todos', todoId], queryFn: () => fetchTodo(todoId) })
useQuery({ queryKey: ['todos', todoId, 'comments'], queryFn: () => fetchComments(todoId) })
// 無効化はプレフィックスマッチ:
// queryClient.invalidateQueries({ queryKey: ['todos'] })
// ^ 'todos' で始まるすべてのクエリを無効化
クエリ関数
// クエリ関数は QueryFunctionContext を受け取ります
useQuery({
queryKey: ['todos', todoId],
queryFn: async ({ queryKey, signal, meta }) => {
const [_key, id] = queryKey
const response = await fetch(`/api/todos/${id}`, { signal })
if (!response.ok) throw new Error('Failed to fetch')
return response.json()
},
})
// 自動キャンセル用の signal を使用
useQuery({
queryKey: ['todos'],
queryFn: async ({ signal }) => {
const response = await fetch('/api/todos', { signal })
return response.json()
},
})
queryOptions ヘルパー
再利用可能で型安全なクエリ設定を作成:
import { queryOptions } from '@tanstack/react-query'
export const todosQueryOptions = queryOptions({
queryKey: ['todos'],
queryFn: fetchTodos,
staleTime: 5000,
})
export const todoQueryOptions = (todoId: string) =>
queryOptions({
queryKey: ['todos', todoId],
queryFn: () => fetchTodo(todoId),
enabled: !!todoId,
})
// 使用方法
const { data } = useQuery(todosQueryOptions)
const { data } = useSuspenseQuery(todoQueryOptions(id))
await queryClient.prefetchQuery(todosQueryOptions)
クエリ (useQuery)
基本的な使用方法
import { useQuery } from '@tanstack/react-query'
function Todos() {
const {
data,
error,
isLoading, // 初回ロード、まだデータなし
isFetching, // フェッチ進行中(バックグラウンド含む)
isError,
isSuccess,
isPending, // まだデータなし(ほとんどの場合 isLoading と同じ)
status, // 'pending' | 'error' | 'success'
fetchStatus, // 'fetching' | 'paused' | 'idle'
refetch,
isStale,
isPlaceholderData,
dataUpdatedAt,
errorUpdatedAt,
} = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
})
if (isLoading) return <Spinner />
if (isError) return <Error message={error.message} />
return <TodoList todos={data} />
}
クエリオプション
useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
// 鮮度
staleTime: 5000, // データが新鮮な状態を保つ ms(デフォルト: 0)
gcTime: 300000, // キャッシュに未使用データが残る ms(デフォルト: 5分)
// リフェッチ
refetchInterval: 10000, // 10秒ごとにポーリング
refetchIntervalInBackground: false, // タブが隠れている時はポーリングしない
refetchOnMount: true, // マウント時に古いデータがあればリフェッチ
refetchOnWindowFocus: true, // ウィンドウフォーカス時に古いデータがあればリフェッチ
refetchOnReconnect: true, // ネットワーク再接続時にリフェッチ
// リトライ
retry: 3, // リトライ回数(または関数)
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
// 条件付き
enabled: !!userId, // 真の値の時のみ実行
// 初期/プレースホルダーデータ
initialData: () => cachedData,
initialDataUpdatedAt: Date.now() - 10000,
placeholderData: (previousData) => previousData, // keepPreviousData パターン
placeholderData: initialTodos,
// 変換
select: (data) => data.filter(todo => !todo.done),
// 構造的共有(デフォルト: true)
structuralSharing: true,
// ネットワークモード
networkMode: 'online', // 'online' | 'always' | 'offlineFirst'
// メタ(クエリ関数コンテキストでアクセス可能)
meta: { purpose: 'user-facing' },
})
ミューテーション (useMutation)
基本的な使用方法
import { useMutation, useQueryClient } from '@tanstack/react-query'
function AddTodo() {
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: (newTodo: { title: string }) => {
return fetch('/api/todos', {
method: 'POST',
body: JSON.stringify(newTodo),
}).then(res => res.json())
},
// ライフサイクルコールバック
onMutate: async (variables) => {
// mutationFn の前に呼ばれます
// 楽観的更新に適切です
return { previousTodos } // onError 用のコンテキスト
},
onSuccess: (data, variables, context) => {
// 関連クエリを無効化
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
onError: (error, variables, context) => {
// 楽観的更新をロールバック
queryClient.setQueryData(['todos'], context.previousTodos)
},
onSettled: (data, error, variables, context) => {
// 常に実行(成功またはエラー)
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
})
return (
<button
onClick={() => mutation.mutate({ title: 'New Todo' })}
disabled={mutation.isPending}
>
{mutation.isPending ? 'Adding...' : 'Add Todo'}
</button>
)
}
ミューテーション状態
const {
mutate, // ファイア・アンド・フォーゲット
mutateAsync, // プロミスを返す
isPending, // ミューテーション進行中
isError,
isSuccess,
isIdle, // まだ実行されていない
data, // 成功レスポンス
error, // エラーオブジェクト
reset, // 状態をアイドルにリセット
variables, // mutate に渡された変数
status, // 'idle' | 'pending' | 'error' | 'success'
} = useMutation({ ... })
楽観的更新
const mutation = useMutation({
mutationFn: updateTodo,
onMutate: async (newTodo) => {
// 1. 送信中のリフェッチをキャンセル
await queryClient.cancelQueries({ queryKey: ['todos', newTodo.id] })
// 2. 前の値をスナップショット
const previousTodo = queryClient.getQueryData(['todos', newTodo.id])
// 3. 楽観的に更新
queryClient.setQueryData(['todos', newTodo.id], newTodo)
// 4. ロールバック用のコンテキストを返す
return { previousTodo }
},
onError: (err, newTodo, context) => {
// エラー時はロールバック
queryClient.setQueryData(['todos', newTodo.id], context.previousTodo)
},
onSettled: () => {
// 常にリフェッチしてサーバーと同期
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
})
リスト上の楽観的更新
onMutate: async (newTodo) => {
await queryClient.cancelQueries({ queryKey: ['todos'] })
const previousTodos = queryClient.getQueryData(['todos'])
queryClient.setQueryData(['todos'], (old) => [...old, newTodo])
return { previousTodos }
},
onError: (err, newTodo, context) => {
queryClient.setQueryData(['todos'], context.previousTodos)
},
クエリ無効化
const queryClient = useQueryClient()
// すべてのクエリを無効化
queryClient.invalidateQueries()
// プレフィックスで無効化
queryClient.invalidateQueries({ queryKey: ['todos'] })
// 完全一致で無効化
queryClient.invalidateQueries({ queryKey: ['todos', 1], exact: true })
// 述語で無効化
queryClient.invalidateQueries({
predicate: (query) =>
query.queryKey[0] === 'todos' && query.queryKey[1]?.status === 'done',
})
// 無効化して即座にリフェッチ
queryClient.refetchQueries({ queryKey: ['todos'] })
// キャッシュから完全に削除
queryClient.removeQueries({ queryKey: ['todos', 1] })
// 初期状態にリセット
queryClient.resetQueries({ queryKey: ['todos'] })
無限クエリ
import { useInfiniteQuery } from '@tanstack/react-query'
function InfiniteList() {
const {
data,
fetchNextPage,
fetchPreviousPage,
hasNextPage,
hasPreviousPage,
isFetchingNextPage,
isFetchingPreviousPage,
} = useInfiniteQuery({
queryKey: ['projects'],
queryFn: async ({ pageParam }) => {
const res = await fetch(`/api/projects?cursor=${pageParam}`)
return res.json()
},
initialPageParam: 0,
getNextPageParam: (lastPage, allPages, lastPageParam) => {
return lastPage.nextCursor ?? undefined // undefined = ページなし
},
getPreviousPageParam: (firstPage, allPages, firstPageParam) => {
return firstPage.prevCursor ?? undefined
},
maxPages: 3, // キャッシュに最大3ページ保持(パフォーマンス用)
})
return (
<div>
{data.pages.map((page) =>
page.items.map((item) => <Item key={item.id} item={item} />)
)}
<button
onClick={() => fetchNextPage()}
disabled={!hasNextPage || isFetchingNextPage}
>
{isFetchingNextPage ? 'Loading...' : hasNextPage ? 'Load More' : 'No more'}
</button>
</div>
)
}
並列クエリ
// 複数の独立したクエリは自動的に並列で実行
function Dashboard() {
const usersQuery = useQuery({ queryKey: ['users'], queryFn: fetchUsers })
const projectsQuery = useQuery({ queryKey: ['projects'], queryFn: fetchProjects })
// 両方が同時にフェッチされます
}
// useQueries で動的な並列クエリ
function UserProjects({ userIds }) {
const queries = useQueries({
queries: userIds.map((id) => ({
queryKey: ['user', id],
queryFn: () => fetchUser(id),
})),
combine: (results) => ({
data: results.map(r => r.data),
pending: results.some(r => r.isPending),
}),
})
}
依存クエリ
// enabled を使用した順序付きクエリ
function UserPosts({ userId }) {
const userQuery = useQuery({
queryKey: ['user', userId],
queryFn: () => fetchUser(userId),
})
const postsQuery = useQuery({
queryKey: ['posts', userId],
queryFn: () => fetchPostsByUser(userId),
enabled: !!userQuery.data, // ユーザーがロードされた時のみ実行
})
}
ページネーション付きクエリ
function PaginatedList() {
const [page, setPage] = useState(1)
const { data, isPlaceholderData } = useQuery({
queryKey: ['todos', page],
queryFn: () => fetchTodos(page),
placeholderData: (previousData) => previousData, // 古いデータを表示し続ける
})
return (
<div style={{ opacity: isPlaceholderData ? 0.5 : 1 }}>
{data.items.map(item => <Item key={item.id} item={item} />)}
<button
onClick={() => setPage(p => p + 1)}
disabled={isPlaceholderData || !data.hasMore}
>
Next
</button>
</div>
)
}
Suspense 統合
import { useSuspenseQuery, useSuspenseInfiniteQuery } from '@tanstack/react-query'
// データがロードされるまでコンポーネントは suspend します
function TodoList() {
const { data } = useSuspenseQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
})
// ここで data は必ず定義されています
return <ul>{data.map(todo => <li key={todo.id}>{todo.title}</li>)}</ul>
}
// Suspense バウンダリでラップ
function App() {
return (
<ErrorBoundary fallback={<Error />}>
<Suspense fallback={<Loading />}>
<TodoList />
</Suspense>
</ErrorBoundary>
)
}
// 複数の suspense クエリ(並列フェッチ)
function Dashboard() {
const [{ data: users }, { data: projects }] = useSuspenseQueries({
queries: [
{ queryKey: ['users'], queryFn: fetchUsers },
{ queryKey: ['projects'], queryFn: fetchProjects },
],
})
}
プリフェッチング
const queryClient = useQueryClient()
// ホバー時にプリフェッチ
function TodoLink({ todoId }) {
const prefetch = () => {
queryClient.prefetchQuery({
queryKey: ['todo', todoId],
queryFn: () => fetchTodo(todoId),
staleTime: 5000, // データが5秒より古い場合のみプリフェッチ
})
}
return (
<Link to={`/todos/${todoId}`} onMouseEnter={prefetch}>
Todo {todoId}
</Link>
)
}
// ルートローダーでプリフェッチ(TanStack Router 統合)
export const Route = createFileRoute('/todos/$todoId')({
loader: ({ context: { queryClient }, params: { todoId } }) =>
queryClient.ensureQueryData(todoQueryOptions(todoId)),
})
// 無限クエリをプリフェッチ
queryClient.prefetchInfiniteQuery({
queryKey: ['projects'],
queryFn: fetchProjects,
initialPageParam: 0,
pages: 3, // 最初の3ページをプリフェッチ
})
SSR とハイドレーション
サーバーサイドプリフェッチング
// サーバーコンポーネントまたはローダー
import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query'
async function getServerSideProps() {
const queryClient = new QueryClient()
await queryClient.prefetchQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
})
return {
props: {
dehydratedState: dehydrate(queryClient),
},
}
}
function Page({ dehydratedState }) {
return (
<HydrationBoundary state={dehydratedState}>
<Todos />
</HydrationBoundary>
)
}
ストリーミング SSR(React Server Components)
import { dehydrate, HydrationBoundary } from '@tanstack/react-query'
import { makeQueryClient } from './query-client'
export default async function Page() {
const queryClient = makeQueryClient()
// サーバーでプリフェッチ
await queryClient.prefetchQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
})
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<TodoList />
</HydrationBoundary>
)
}
QueryClient API
const queryClient = useQueryClient()
// キャッシュされたデータを取得
queryClient.getQueryData(['todos'])
// キャッシュされたデータを設定
queryClient.setQueryData(['todos'], updatedTodos)
queryClient.setQueryData(['todos'], (old) => [...old, newTodo])
// クエリ状態を取得
queryClient.getQueryState(['todos'])
// フェッチ中かチェック
queryClient.isFetching({ queryKey: ['todos'] })
queryClient.isMutating()
// クエリをキャンセル
queryClient.cancelQueries({ queryKey: ['todos'] })
// 無効化(古いとマーク、アクティブなものはリフェッチ)
queryClient.invalidateQueries({ queryKey: ['todos'] })
// リフェッチ(新鮮でも強制的にリフェッチ)
queryClient.refetchQueries({ queryKey: ['todos'] })
// キャッシュから削除
queryClient.removeQueries({ queryKey: ['todos'] })
// 初期状態にリセット
queryClient.resetQueries({ queryKey: ['todos'] })
// キャッシュ全体をクリア
queryClient.clear()
// プリフェッチ
queryClient.prefetchQuery({ queryKey: ['todos'], queryFn: fetchTodos })
queryClient.ensureQueryData({ queryKey: ['todos'], queryFn: fetchTodos })
// デフォルト値を取得/設定
queryClient.setQueryDefaults(['todos'], { staleTime: 10000 })
queryClient.getQueryDefaults(['todos'])
queryClient.setMutationDefaults(['addTodo'], { mutationFn: addTodo })
テスト
import { renderHook, waitFor } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
function createWrapper() {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false, // テストではリトライしない
gcTime: Infinity, // テスト中のキャッシュクリーンアップを防止
},
},
})
return ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
)
}
test('fetches todos', async () => {
const { result } = renderHook(() => useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
}), { wrapper: createWrapper() })
await waitFor(() => expect(result.current.isSuccess).toBe(true))
expect(result.current.data).toEqual(expectedTodos)
})
// コンポーネントテスト用に setQueryData でモック
test('renders todos', () => {
const queryClient = new QueryClient()
queryClient.setQueryData(['todos'], mockTodos)
render(
<QueryClientProvider client={queryClient}>
<TodoList />
</QueryClientProvider>
)
expect(screen.getByText('Todo 1')).toBeInTheDocument()
})
TypeScript パターン
クエリ関数の型付け
interface Todo {
id: number
title: string
completed: boolean
}
// 型は queryFn の戻り値の型から推論
const { data } = useQuery({
queryKey: ['todos'],
queryFn: async (): Promise<Todo[]> => {
const res = await fetch('/api/todos')
return res.json()
},
})
// data: Todo[] | undefined
// select 付き
const { data } = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
select: (data): string[] => data.map(t => t.title),
})
// data: string[] | undefined
エラーの型付け
// デフォルトのエラー型は Error です
const { error } = useQuery<Todo[], AxiosError>({
queryKey: ['todos'],
queryFn: fetchTodos,
})
// またはグローバルに登録
declare module '@tanstack/react-query' {
interface Register {
defaultError: AxiosError
}
}
クエリオプションパターン(推奨)
import { queryOptions, infiniteQueryOptions } from '@tanstack/react-query'
export const todosOptions = queryOptions({
queryKey: ['todos'] as const,
queryFn: fetchTodos,
staleTime: 5000,
})
export const todoOptions = (id: string) =>
queryOptions({
queryKey: ['todos', id] as const,
queryFn: () => fetchTodo(id),
enabled: !!id,
})
// どこでも完全な型推論
const { data } = useQuery(todosOptions)
const { data } = useSuspenseQuery(todoOptions('123'))
await queryClient.ensureQueryData(todosOptions)
queryClient.invalidateQueries({ queryKey: todosOptions.queryKey })
高度なパターン
ウィンドウフォーカスリフェッチング
// グローバルに無効化
const queryClient = new QueryClient({
defaultOptions: {
queries: { refetchOnWindowFocus: false },
},
})
// カスタムフォーカスマネージャー
import { focusManager } from '@tanstack/react-query'
// React Native 向け
focusManager.setEventListener((handleFocus) => {
const subscription = AppState.addEventListener('change', (state) => {
handleFocus(state === 'active')
})
return () => subscription.remove()
})
ネットワークモード
useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
// 'online'(デフォルト): オンライン時のみフェッチ
// 'always': 常にフェッチ(local-first に便利)
// 'offlineFirst': フェッチしてみて、オフライン時はキャッシュ使用
networkMode: 'offlineFirst',
})
クエリキャンセレーション
useQuery({
queryKey: ['todos'],
queryFn: async ({ signal }) => {
// signal は AbortSignal - アンマウント時またはキー変更時に自動キャンセル
const res = await fetch('/api/todos', { signal })
return res.json()
},
})
// 手動キャンセレーション
queryClient.cancelQueries({ queryKey: ['todos'] })
永続化
import { persistQueryClient } from '@tanstack/react-query-persist-client'
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'
const persister = createSyncStoragePersister({
storage: window.localStorage,
})
persistQueryClient({
queryClient,
persister,
maxAge: 1000 * 60 * 60 * 24, // 24時間
})
ベストプラクティス
queryOptionsヘルパーを使用 - 型安全で再利用可能なクエリ設定用- クエリキーを階層的に構造化 - きめ細かな無効化用
- 適切な
staleTimeを設定 - 0 はマウント時に常にリフェッチ(デフォルト)、動的でないデータは増加させる placeholderDataを使用(initialDataではなく)- ページネーション時の前ページデータ保持用- Suspense バウンダリ使用時は
useSuspenseQueryを推奨 - コンポーネントコードがクリーン - 条件付きフック呼び出しではなく
enabledを使用 - 依存クエリ用 - ミューテーション後は常に無効化 - 楽観的更新だけに頼らない
onMutateで楽観的更新前にクエリをキャンセル - 競合状態の防止prefetchQueryではなくensureQueryDataをルートローダーで使用 - 即座アクセス用- テストで
retry: falseを設定 - タイムアウト問題を回避 - クエリ結果を分割代入しない(持ち運ぶ場合)- リアクティビティを破壊
- コンポーネントの変換ではなく
selectを使用 - 派生データ用 - クエリ関数を純粋に保つ - フェッチのみ、副作用なし
- テストで
gcTime: Infinityを使用 - アサーション時のキャッシュクリーンアップを防止
よくあるピットフォール
placeholderDataの代わりにinitialDataを使用(initialData は「新鮮な」データとしてカウント)- 無限クエリに
initialPageParamを提供し忘れ(v5 で必須) - 条件付きでフックを呼び出す(React ルール違反)
- 楽観的更新前にクエリをキャンセルしない(競合状態)
staleTimeをgcTimeより高く設定(「新鮮な」間にデータがガベージコレクション)- テストを
QueryClientProviderでラップし忘れ - テスト間で同じ
QueryClientインスタンスを使用(共有状態) - 順序が重要な場合、ミューテーションコールバックで
invalidateQueriesを await し忘れ
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- tanstack-skills
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/tanstack-skills/tanstack-skills / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。