You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在页面跳转前预加载下一页的服务端数据?

How to Fetch Server Data Before Navigating to the Next Page (After SSR Preloaded First Screen)

Great question! Since you're already leveraging SSR with Redux and window.__PRELOAD_STATE__ for your first screen, handling data fetching on subsequent navigation boils down to a few common, reliable patterns—let's walk through them:

1. Use Router-Level Data Fetching (Framework-Specific)

If you're using a framework like Next.js or React Router v6+, built-in router features are the most straightforward way to handle this. These tools let you define data fetching logic that runs before navigation completes, whether it's a client-side route change or a fresh server request.

Example with Next.js (getServerSideProps)

For client-side navigation (using next/link), Next.js will still trigger getServerSideProps in the background before rendering the new page. You can pass the fetched data to your Redux store during this step:

// pages/posts/[id].js
export async function getServerSideProps(context) {
  const { id } = context.params;
  // Fetch data from your server
  const res = await fetch(`https://your-api.com/posts/${id}`);
  const post = await res.json();

  // Pass data to the page via props, then dispatch to Redux
  return {
    props: { initialPostData: post },
  };
}

function PostPage({ initialPostData }) {
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(setPost(initialPostData));
  }, [dispatch, initialPostData]);

  // Render your component using Redux state
  return <div>{/* ... */}</div>;
}

Example with React Router v6+ (Loader Function)

React Router's loaders run before the route renders, even on client-side navigation. You can access the loader data via useLoaderData and sync it to Redux:

// router.js
const router = createBrowserRouter([
  {
    path: "/posts/:id",
    element: <PostPage />,
    loader: async ({ params }) => {
      const res = await fetch(`https://your-api.com/posts/${params.id}`);
      return res.json();
    },
  },
]);

// PostPage.jsx
function PostPage() {
  const postData = useLoaderData();
  const dispatch = useDispatch();
  
  useEffect(() => {
    dispatch(setPost(postData));
  }, [dispatch, postData]);

  return <div>{/* ... */}</div>;
}

2. Custom Navigation Component with Preloading

If you need more control (or aren't using a framework with built-in router fetching), you can wrap your navigation links to intercept clicks, fetch data first, update Redux, then navigate.

import { useDispatch, useNavigate } from "react-router-dom";
import { fetchPost } from "./redux/actions";
import { useState } from "react";

function PreloadLink({ to, postId, children }) {
  const dispatch = useDispatch();
  const navigate = useNavigate();
  const [isLoading, setIsLoading] = useState(false);

  const handleClick = async (e) => {
    e.preventDefault();
    if (isLoading) return;

    setIsLoading(true);
    try {
      // Fetch data and update Redux first
      await dispatch(fetchPost(postId)).unwrap();
      // Navigate only after data is in the store
      navigate(to);
    } catch (error) {
      // Handle error (e.g., show toast, log)
      console.error("Failed to fetch post:", error);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <a href={to} onClick={handleClick} disabled={isLoading}>
      {isLoading ? "Loading..." : children}
    </a>
  );
}

3. Redux Middleware/Async Actions (Thunks/Sagas)

If you're using Redux Thunk or Redux Saga, you can structure your async actions to resolve only after data is fetched and stored, then trigger navigation once the action completes.

Example with Redux Thunk

// actions.js
export const fetchPostAndNavigate = (postId, navigatePath) => async (dispatch) => {
  try {
    const res = await fetch(`https://your-api.com/posts/${postId}`);
    const post = await res.json();
    dispatch(setPost(post));
    // Navigate after successful dispatch
    window.location.href = navigatePath;
    // Or use React Router's navigate:
    // navigate(navigatePath);
  } catch (error) {
    dispatch(setPostError(error));
  }
};

// In your component
function PostLink({ postId, to }) {
  const dispatch = useDispatch();

  const handleClick = () => {
    dispatch(fetchPostAndNavigate(postId, to));
  };

  return <button onClick={handleClick}>View Post</button>;
}

Key Notes to Keep in Mind

  • Loading States: Always add loading indicators to prevent users from clicking multiple times while data is fetching.
  • Error Handling: Make sure to catch and display errors if the server request fails—don't leave users hanging!
  • Data Consistency: If your app is fully isomorphic, ensure that client-side fetching logic matches what you use on the server to avoid hydration mismatches.

内容的提问来源于stack exchange,提问作者MAMA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:59:46