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

Next.js 13.4.10中如何在同页面实现SSR与投票类客户端交互

在Next.js 13.4.10中同时实现SSR内容交付与客户端投票交互

完全可以实现,Next.js 13+的App Router支持服务器组件与客户端组件混合使用,刚好能满足你的需求:服务器组件负责SSR渲染帖子内容(保证搜索引擎可见),客户端组件封装投票交互逻辑(仅在客户端执行)。

具体实现步骤:

1. 拆分投票交互为客户端组件

创建独立的VoteButton.tsx组件,添加'use client'指令标记为客户端组件,在内部处理投票逻辑与本地状态更新:

'use client';

import { useState } from 'react';

interface VoteButtonProps {
  postId: number;
  initialVote: number;
}

export default function VoteButton({ postId, initialVote }: VoteButtonProps) {
  const [voteCount, setVoteCount] = useState(initialVote);

  const handleVote = async (direction: number) => {
    // 调用后端API更新票数
    await fetch(`/api/vote/${postId}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ vote: direction }),
    });
    // 本地即时更新票数,提升用户体验
    setVoteCount(prev => prev + direction);
  };

  return (
    <div>
      <p>vote: {voteCount}</p>
      <button onClick={() => handleVote(1)}> + </button>{' '}
      <button onClick={() => handleVote(-1)}> - </button>
    </div>
  );
}

2. 保留主页为服务器组件

原Home组件作为服务器组件(无需'use client'),负责在服务器端获取数据、渲染帖子内容,并引入客户端投票组件:

interface Post {
  id: number;
  title: string;
  body: string;
  vote: number;
}

async function getPosts(): Promise<Post[]> {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts', {
    next: { revalidate: 60 }, // 可选:设置60秒自动重新验证,实现增量静态再生
  });
  // 注意:jsonplaceholder返回的帖子无vote字段,手动添加默认值
  const posts = await res.json();
  return posts.map(post => ({ ...post, vote: 0 }));
}

import VoteButton from './VoteButton';

export default async function Home() {
  const posts = await getPosts();
  return (
    <>
      {posts.map((post: Post) => (
        <div key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.body}</p>
          <VoteButton postId={post.id} initialVote={post.vote} />
        </div>
      ))}
    </>
  );
}

3. 创建API路由处理投票请求

在app/api/vote/[postId]/route.ts中编写后端逻辑,处理票数更新:

import { NextResponse } from 'next/server';

export async function POST(
  request: Request,
  { params }: { params: { postId: string } }
) {
  const { vote } = await request.json();
  const postId = params.postId;

  // 替换为你的实际业务逻辑:比如操作数据库更新对应帖子的票数
  console.log(`Post ${postId} 票数更新:${vote > 0 ? '+' : ''}${vote}`);

  return NextResponse.json({ success: true });
}

核心原理:

  • 服务器组件(Home):在服务器端完成数据获取与HTML渲染,生成的静态内容能被搜索引擎正常抓取,完全符合SSR需求。
  • 客户端组件(VoteButton):仅在客户端加载并执行JS,处理点击事件与状态更新,不会影响服务器端渲染的内容。两者通过props传递初始数据,实现无缝结合。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 09:52:47