従来の fetch useState useEffect
アプローチを React-TanStack-Query に置き換えることについての以前の議論を思い出してください。 QueryProvider
の設定、基本的なクエリの作成、突然変異の処理などの基本を使用している場合は、おそらくすでにその利点を経験しているでしょう。 ただし、私たちはその機能の探索を始めたばかりです。
データの取得を大幅に強化し、アプリケーションのパフォーマンスを「良好」から「非常に高速」に変える高度なテクニックをさらに深く掘り下げてみましょう。
前のガイドでは、React-TanStack-Query を使用した基本的な映画リストを示しました。
<code class="language-javascript">const { data: movies, error, isLoading } = useQuery(['movies'], fetchMovies);</code>
これは素晴らしい出発点ですが、Netflix レベルの応答性を目指す場合はどうなるでしょうか? 技術を高めていきましょう。
最初の映画リストでは、ユーザーはクリック後に待つ必要がありました。これを大幅に改善できます:
<code class="language-javascript">// components/MovieList.jsx import { useQueryClient } from '@tanstack/react-query'; export default function MovieList() { const queryClient = useQueryClient(); // Leveraging our existing fetchMovies function const prefetchMovie = async (movieId) => { await queryClient.prefetchQuery({ queryKey: ['movie', movieId], queryFn: () => fetchMovieDetails(movieId), // Maintain freshness for 5 minutes staleTime: 5 * 60 * 1000, }); }; return ( <div className="grid grid-cols-4 gap-4"> {movies.map(movie => ( <div key={movie.id} onMouseEnter={() => prefetchMovie(movie.id)} className="movie-card" > {movie.title} </div> ))} </div> ); }</code>
ユーザーがムービーの上にマウスを移動すると、詳細が事前に読み込まれ、クリックするとすぐにアクセスできるようになりました。 ✨
私たちの最初の記事では、基本的な突然変異について説明しました。楽観的な更新でそれらを最適化しましょう:
<code class="language-javascript">// hooks/useUpdateMovie.js export function useUpdateMovie() { const queryClient = useQueryClient(); return useMutation({ mutationFn: updateMovie, // The key improvement onMutate: async (newMovie) => { // Halt ongoing refetches await queryClient.cancelQueries(['movie', newMovie.id]); // Store current state (for rollback if needed) const previousMovie = queryClient.getQueryData(['movie', newMovie.id]); // Immediate (optimistic) update queryClient.setQueryData(['movie', newMovie.id], newMovie); return { previousMovie }; }, // Error handling onError: (err, newMovie, context) => { queryClient.setQueryData( ['movie', newMovie.id], context.previousMovie ); }, }); }</code>
順次読み込みは過去のものです:
<code class="language-javascript">// pages/movie/[id].js export default function MoviePage({ movieId }) { const results = useQueries({ queries: [ { queryKey: ['movie', movieId], queryFn: () => fetchMovie(movieId), }, { queryKey: ['cast', movieId], queryFn: () => fetchCast(movieId), }, { queryKey: ['reviews', movieId], queryFn: () => fetchReviews(movieId), }, ], }); if (results.some(result => result.isLoading)) { return <LoadingSpinner />; } const [movie, cast, reviews] = results.map(r => r.data); return <MovieDetails cast={cast} movie={movie} reviews={reviews} />; }</code>
ページ分割された例をシームレスな無限スクロールにアップグレードしてみましょう:
<code class="language-javascript">// components/InfiniteMovieList.jsx import { useInfiniteQuery } from '@tanstack/react-query'; import { useInView } from 'react-intersection-observer'; export default function InfiniteMovieList() { const { ref, inView } = useInView(); const { data, fetchNextPage, hasNextPage, isFetchingNextPage, } = useInfiniteQuery({ queryKey: ['movies'], queryFn: fetchMoviePage, getNextPageParam: (lastPage) => lastPage.nextCursor, }); useEffect(() => { if (inView && hasNextPage) { fetchNextPage(); } }, [inView, hasNextPage]); return ( <div> {data.pages.map((page) => ( page.movies.map((movie) => ( <MovieCard key={movie.id} movie={movie} /> )) ))} <div ref={ref}> {isFetchingNextPage ? <LoadingSpinner /> : null} </div> </div> ); }</code>
これは、最初の記事「Next.js 14 サーバー コンポーネントの統合」では利用できない機能です。
<code class="language-javascript">const { data: movies, error, isLoading } = useQuery(['movies'], fetchMovies);</code>
<code class="language-javascript">// components/MovieList.jsx import { useQueryClient } from '@tanstack/react-query'; export default function MovieList() { const queryClient = useQueryClient(); // Leveraging our existing fetchMovies function const prefetchMovie = async (movieId) => { await queryClient.prefetchQuery({ queryKey: ['movie', movieId], queryFn: () => fetchMovieDetails(movieId), // Maintain freshness for 5 minutes staleTime: 5 * 60 * 1000, }); }; return ( <div className="grid grid-cols-4 gap-4"> {movies.map(movie => ( <div key={movie.id} onMouseEnter={() => prefetchMovie(movie.id)} className="movie-card" > {movie.title} </div> ))} </div> ); }</code>
<code class="language-javascript">// hooks/useUpdateMovie.js export function useUpdateMovie() { const queryClient = useQueryClient(); return useMutation({ mutationFn: updateMovie, // The key improvement onMutate: async (newMovie) => { // Halt ongoing refetches await queryClient.cancelQueries(['movie', newMovie.id]); // Store current state (for rollback if needed) const previousMovie = queryClient.getQueryData(['movie', newMovie.id]); // Immediate (optimistic) update queryClient.setQueryData(['movie', newMovie.id], newMovie); return { previousMovie }; }, // Error handling onError: (err, newMovie, context) => { queryClient.setQueryData( ['movie', newMovie.id], context.previousMovie ); }, }); }</code>
<code class="language-javascript">// pages/movie/[id].js export default function MoviePage({ movieId }) { const results = useQueries({ queries: [ { queryKey: ['movie', movieId], queryFn: () => fetchMovie(movieId), }, { queryKey: ['cast', movieId], queryFn: () => fetchCast(movieId), }, { queryKey: ['reviews', movieId], queryFn: () => fetchReviews(movieId), }, ], }); if (results.some(result => result.isLoading)) { return <LoadingSpinner />; } const [movie, cast, reviews] = results.map(r => r.data); return <MovieDetails cast={cast} movie={movie} reviews={reviews} />; }</code>
初期設定から大幅に進歩しました!これらの機能強化は、真に優れたユーザー エクスペリエンスを作成するために非常に重要です。
すべてを一度に実装する必要はないことに注意してください。基本から始めて、必要に応じてこれらの最適化を段階的に組み込んでいきます。
次回誰かがあなたのアプリケーションの速度についてコメントするとき、あなたはそれがなぜそれほど素晴らしいのかを正確に知ることになるでしょう。 ?
コーディングを楽しんでください! React-TanStack-Query は無限の可能性を提供します。次は何を調べましょう?
以上がReact-TanStack-Query を Next.js で次のレベルに引き上げるの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。