Vous vous souvenez de notre discussion précédente sur le remplacement de l'approche traditionnelle fetch useState useEffect
par React-TanStack-Query ? Si vous avez utilisé les principes fondamentaux (configuration de QueryProvider
, rédaction de requêtes de base et gestion des mutations), vous en avez probablement déjà profité. Cependant, nous commençons tout juste à explorer ses capacités.
Approfondissons les techniques avancées qui amélioreront considérablement la récupération de vos données, transformant les performances de votre application de « bonnes » à « exceptionnellement rapides ».
Notre guide précédent présentait une liste de films de base à l'aide de React-TanStack-Query :
<code class="language-javascript">const { data: movies, error, isLoading } = useQuery(['movies'], fetchMovies);</code>
C'est un excellent point de départ, mais et si nous visions une réactivité de niveau Netflix ? Élevons nos techniques.
Notre liste de films initiale obligeait les utilisateurs à attendre après avoir cliqué. Nous pouvons considérablement améliorer cela :
<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>
Désormais, lorsque les utilisateurs survolent un film, les détails sont préchargés : accès instantané en cliquant ! ✨
Notre article initial couvrait les mutations fondamentales. Optimisons-les avec des mises à jour optimistes :
<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>
Le chargement séquentiel appartient au passé :
<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>
Améliorons notre exemple paginé vers un défilement infini transparent :
<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>
Il s'agit d'une fonctionnalité non disponible dans notre premier article : Intégration des composants serveur 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>
Nous avons considérablement avancé par rapport à notre configuration initiale ! Ces améliorations sont cruciales pour créer une expérience utilisateur vraiment exceptionnelle.
N'oubliez pas que vous n'avez pas besoin de tout mettre en œuvre en même temps. Commencez par les bases, puis intégrez progressivement ces optimisations selon les besoins.
La prochaine fois que quelqu'un commentera la vitesse de votre application, vous saurez exactement pourquoi elle est si impressionnante. ?
Bon codage ! React-TanStack-Query offre des possibilités infinies. Que devrions-nous explorer ensuite ?
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!