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

Next.js Router响应缓慢问题排查与优化方案咨询

你的路由切换慢确实大概率是getServerSideProps导致的——这个函数会每次用户访问首页(包括从其他路由切过来)时,都在服务器端发起一次API请求,请求完成后才会返回页面,自然拖慢了响应速度。不需要替换成React Router,Next.js自带的路由系统本身是高效的,核心问题在数据获取逻辑,给你几个针对性的修改方案:

方案一:改用静态生成(SSG)+ 增量静态再生(ISR)(推荐)

如果你的视频数据不需要实时更新(比如允许5-10分钟的缓存),这个方案最快,页面会提前生成并缓存,后续请求直接返回静态文件。

修改首页的getServerSideProps为getStaticProps,并加上revalidate参数实现自动更新:

// 首页代码修改后的getStaticProps
export const getStaticProps = async () => {
  const response = await axios.get(`${BASE_URL}/api/post`);
  
  return {
    props: { videos: response.data },
    revalidate: 300, // 每5分钟(300秒)重新生成一次页面
  };
};

如果需要支持topic查询参数的动态路由,把首页改成动态路由(比如pages/[topic].tsx),再配合getStaticPaths预生成常见页面:

// 动态路由页面的getStaticPaths
export const getStaticPaths = async () => {
  // 先获取所有可能的topic列表
  const topicsRes = await axios.get(`${BASE_URL}/api/discover/topics`);
  const paths = topicsRes.data.map((topic: string) => ({
    params: { topic },
  }));

  return {
    paths,
    fallback: 'blocking', // 未预生成的topic会在首次访问时生成并缓存
  };
};

export const getStaticProps = async ({ params }: { params: { topic: string } }) => {
  const { topic } = params;
  let response;
  if(topic) {
    response = await axios.get(`${BASE_URL}/api/discover/${topic}`);
  } else {
    response = await axios.get(`${BASE_URL}/api/post`);
  }
  
  return {
    props: { videos: response.data },
    revalidate: 300,
  };
};

方案二:改用客户端数据获取

如果数据必须实时更新,把请求移到组件内部,用useEffect或者数据缓存库(比如SWR)实现,路由切换时页面先渲染加载状态,数据加载完成后再更新,用户感知更流畅,还能自动缓存请求结果。

用useEffect实现:

// 修改后的首页组件
import axios from 'axios';
import { useState, useEffect } from 'react';
import VideoCard from '../components/VideoCard';
import { BASE_URL } from '../utils';
import { Video } from '../types';
import NoResults from '../components/NoResults';

const Home = () => {
  const [videos, setVideos] = useState<Video[]>([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchVideos = async () => {
      const urlParams = new URLSearchParams(window.location.search);
      const topic = urlParams.get('topic');
      
      let response;
      if(topic) {
        response = await axios.get(`${BASE_URL}/api/discover/${topic}`);
      } else {
        response = await axios.get(`${BASE_URL}/api/post`);
      }
      
      setVideos(response.data);
      setLoading(false);
    };

    fetchVideos();
  }, []);

  if(loading) {
    return <div className="flex items-center justify-center h-full">加载中...</div>; // 可替换为骨架屏
  }

  return (
    <div className='flex flex-col gap-10 videos h-full'>
      {videos.length 
        ? videos?.map((video: Video) => (
          <VideoCard post={video} isShowingOnHome key={video._id} />
        )) 
        : <NoResults text={`No Videos`} />}
    </div>
  );
};

export default Home;

用SWR优化(推荐,自带缓存、重试等功能)

先安装SWR:npm install swr

import axios from 'axios';
import useSWR from 'swr';
import VideoCard from '../components/VideoCard';
import { BASE_URL } from '../utils';
import { Video } from '../types';
import NoResults from '../components/NoResults';

const fetcher = async (url: string) => {
  const response = await axios.get(url);
  return response.data;
};

const Home = () => {
  const urlParams = new URLSearchParams(window.location.search);
  const topic = urlParams.get('topic');
  const apiUrl = topic ? `${BASE_URL}/api/discover/${topic}` : `${BASE_URL}/api/post`;

  const { data: videos, error, isLoading } = useSWR(apiUrl, fetcher);

  if(isLoading) {
    return <div className="flex items-center justify-center h-full">加载中...</div>;
  }

  if(error) {
    return <div className="flex items-center justify-center h-full">加载失败,请重试</div>;
  }

  return (
    <div className='flex flex-col gap-10 videos h-full'>
      {videos?.length 
        ? videos?.map((video: Video) => (
          <VideoCard post={video} isShowingOnHome key={video._id} />
        )) 
        : <NoResults text={`No Videos`} />}
    </div>
  );
};

export default Home;

方案三:优化getServerSideProps(临时过渡方案)

如果暂时不想改数据获取方式,可以给API请求加内存缓存,减少重复请求:

export const getServerSideProps = async ({
  query: { topic },
}: { query: { topic: string }; }) => {
  const cacheKey = topic ? `topic_${topic}` : 'home_videos';
  // 内存缓存1分钟(生产环境建议用Redis等持久化缓存)
  if((global as any)[cacheKey] && Date.now() - (global as any)[cacheKey].timestamp < 60000) {
    return {
      props: { videos: (global as any)[cacheKey].data },
    };
  }

  let response;
  if(topic) {
    response = await axios.get(`${BASE_URL}/api/discover/${topic}`);
  } else {
    response = await axios.get(`${BASE_URL}/api/post`);
  }

  (global as any)[cacheKey] = {
    data: response.data,
    timestamp: Date.now(),
  };
  
  return {
    props: { videos: response.data },
  };
};

另外,你的侧边栏Link组件使用是正确的,Next.js的Link会自动做预加载优化(用户hover链接时提前加载页面),不需要额外调整路由系统。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 09:33:20