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

Next.js 14:如何在CSR页面加载构建时生成的SG页面

实现方案(Next.js 14)

1. 先确保静态生成(SG)页面完成预构建

在app/SG/[id]/product/page.tsx中配置静态生成参数,让Next.js在构建阶段预先生成所有需要的静态页面:

// app/SG/[id]/product/page.tsx
export async function generateStaticParams() {
  // 这里返回所有要预生成的id列表,可从数据库、配置文件等渠道获取
  return [
    { id: '1' },
    { id: '2' },
    { id: '3' }
  ];
}

export default function ProductPage({ params }: { params: { id: string } }) {
  return (
    <div className="product-content">
      <h1>产品 {params.id}</h1>
      <p>这是静态生成的产品 {params.id} 详情内容</p>
    </div>
  );
}

执行next build后,Next.js会自动在构建产物中生成对应id的静态HTML文件,访问路径为/SG/{id}/product。

2. 编写CSR页面的结构与切换逻辑

在app/CSR/page.tsx中实现客户端组件,渲染带data-id的内容容器,同时完成静态HTML的加载与切换:

// app/CSR/page.tsx
'use client';

import { useEffect, useState } from 'react';

export default function CSRPage() {
  const [currentId, setCurrentId] = useState('1');
  const contentCache = new Map<string, string>(); // 缓存已加载的静态内容,避免重复请求

  useEffect(() => {
    loadStaticContent(currentId);
  }, [currentId]);

  const loadStaticContent = async (id: string) => {
    const container = document.querySelector('[data-id="product-container"]');
    if (!container) return;

    // 优先读取缓存
    if (contentCache.has(id)) {
      container.innerHTML = contentCache.get(id)!;
      container.setAttribute('data-id', `product-container-${id}`);
      return;
    }

    try {
      // 请求对应id的静态页面
      const response = await fetch(`/SG/${id}/product`);
      if (!response.ok) throw new Error('静态页面加载失败');
      
      const html = await response.text();
      // 提取静态页面body内的内容,避免替换CSR页面的全局结构
      const tempDiv = document.createElement('div');
      tempDiv.innerHTML = html;
      const content = tempDiv.querySelector('body')?.innerHTML || '';
      
      // 更新容器内容与属性
      container.innerHTML = content;
      container.setAttribute('data-id', `product-container-${id}`);
      contentCache.set(id, content);
    } catch (err) {
      console.error('加载静态内容出错:', err);
      container.innerHTML = `<p>加载产品 ${id} 失败,请稍后重试</p>`;
    }
  };

  return (
    <div>
      <h1>CSR 产品切换页面</h1>
      <div className="id-switcher">
        <button onClick={() => setCurrentId('1')}>产品1</button>
        <button onClick={() => setCurrentId('2')}>产品2</button>
        <button onClick={() => setCurrentId('3')}>产品3</button>
      </div>
      {/* 静态内容容器,初始标记data-id */}
      <div data-id="product-container"></div>
    </div>
  );
}

3. 核心逻辑说明

  • 静态页面请求:通过fetch直接访问构建好的静态页面路径,Next.js会返回预生成的HTML文件,无需服务器动态渲染。
  • 内容提取与替换:因为静态页面是完整的HTML文档,所以用临时div解析后提取body内的内容,避免破坏CSR页面的全局结构。
  • 缓存优化:用Map存储已加载的HTML内容,减少重复网络请求,提升切换速度。
  • 属性同步:每次切换id后更新容器的data-id属性,方便后续逻辑识别当前加载的内容标识。

4. 注意事项

  • 如果静态页面包含客户端脚本(比如React hydration逻辑),注入到CSR页面后可能与现有客户端逻辑冲突,建议静态页面仅保留纯静态内容,或确保脚本不会重复执行。
  • 确保next.config.js未禁用静态生成相关配置,Next.js 14 App Router默认支持静态生成,无需额外配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 22:17:33