首頁 > web前端 > js教程 > 在 Next.js 中將 React-TanStack-Query 提升到新的水平

在 Next.js 中將 React-TanStack-Query 提升到新的水平

Linda Hamilton
發布: 2025-01-22 20:40:10
原創
506 人瀏覽過

Taking React-TanStack-Query to the Next Level in Next.js

還記得我們之前關於用 React-TanStack-Query 取代傳統 fetch useState useEffect 方法的討論嗎?如果您一直在使用基礎知識——設定 QueryProvider、編寫基本查詢和處理突變——您可能已經體驗到了這些優勢。 然而,我們才剛開始探索它的功能。

讓我們更深入地研究先進技術,這些技術將顯著增強您的數據獲取,將應用程式的效能從「良好」轉變為「異常快」。

建立更強大的基礎

我們先前的指南示範了使用 React-TanStack-Query 的基本影片清單:

<code class="language-javascript">const { data: movies, error, isLoading } = useQuery(['movies'], fetchMovies);</code>
登入後複製
登入後複製

這是一個很好的起點,但如果我們的目標是 Netflix 等級的反應能力呢? 讓我們提昇技術吧。

先進科技帶來卓越性能

1.智慧預取(實現類似 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>
登入後複製
登入後複製

現在,當用戶將滑鼠懸停在電影上時,詳細資訊就會預先加載 - 點擊即可立即訪問! ✨

2.增強突變(還記得那些嗎?)

我們的第一篇文章涵蓋了基本突變。讓我們透過樂觀更新來優化它們:

<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>
登入後複製
登入後複製

3.並行資料載入(消除不必要的等待)

順序載入已成為過去:

<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>
登入後複製
登入後複製

4.實現無限滾動(高效率的方式)

讓我們將分頁範例升級為無縫無限滾動:

<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>
登入後複製

5.利用 Next.js 14 個伺服器元件

這是我們第一篇文章中不提供的功能:Next.js 14 伺服器元件整合:

<code class="language-javascript">const { data: movies, error, isLoading } = useQuery(['movies'], fetchMovies);</code>
登入後複製
登入後複製

專業提示(經驗教訓)

  1. 一致的查詢鍵:細化我們的電影查詢鍵:
<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>
登入後複製
登入後複製
  1. 智慧型重​​新取得:改進視窗焦點的基本重新取得:
<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>
登入後複製
登入後複製
  1. 強大的錯誤處理:增強我們的基本錯誤處理:
<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 提供了無限的可能性。接下來我們該探索什麼?

以上是在 Next.js 中將 React-TanStack-Query 提升到新的水平的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板