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

Next.js 15中触发服务端动作后如何局部刷新服务端组件UI

Next.js 15 服务端组件局部刷新问题解决方案

问题场景

使用Next.js 15时,需要实现客户端组件触发服务端动作后,无需整页刷新更新服务端组件的UI。简化代码结构如下:

客户端组件

'use client';

import { updateText } from './parent_comp';

export default function ClientComp() {
 const handleClick = async () => {
  await updateText('devtz007'); // 向服务端发送新数据
};
return (
 <button
  onClick={handleClick}
  style={{ color: 'black', background: 'coral' }}
 >
  Send Text
 </button>
 );
}

服务端组件 + 动作

'use server';

import ClientComp from './client_comp';
import { revalidatePath } from 'next/cache';

let text = 'initial text';

export async function updateText(newText: string): Promise<string> {
 text = newText;
  // revalidatePath('/example_page'); // 此方法会重渲染整页,我需要更精准的更新!
  return text;
}

export default async function ParentComp() {
  return (
    <>
      <p style={{ color: 'green', backgroundColor: 'coral' }}>
         Received Text: {text}
        </p>
       <ClientComp />
     </>
    );
}

已尝试方案

  • 使用revalidatePath()可实现更新,但会触发整页刷新。
  • 改用revalidateTag()并添加缓存标签textUpdate,但未达到预期效果:

服务端动作代码

// Server action with revalidateTag
 export async function updateText(
   newText: string,
   options: { next: { tags: string[] } },
 ) {
   if (options.next.tags.includes('textUpdate')) {
     text = newText;
     revalidateTag('textUpdate'); // 应触发相关组件更新
    }
  }

组件代码

export default async function ParentComp() {
   return (
     <>
      <p style={{ color: 'green', backgroundColor: 'coral' }}>{text}</p>
      <ClientComp />
     </>
    );
  }

疑问与解答

1. revalidateTag()是仅重渲染相关部分还是整页?

revalidateTag()不会整页刷新,它只会重新渲染带有对应缓存标签的组件或数据请求。但你的代码未给目标内容打上对应标签,所以当前写法无法生效。

2. 其他页面使用ClientComp后,ParentComp无法立即更新

这是因为revalidateTag()仅作用于关联了对应标签的缓存内容。解决前提是:目标页面的服务端组件/数据请求必须打上相同的缓存标签,这样revalidateTag()才能触发其重新验证。

3. 不想使用router.refresh()

完全合理,router.refresh()本质是整页重新渲染,不符合局部更新需求,无需采用。

4. Next.js 15中局部刷新服务端组件的标准模式

Next.js 15实现服务端组件局部刷新的标准方式是缓存标签(revalidateTag)+ 带标签的服务端数据请求,具体实现步骤如下:

步骤1:给服务端数据请求添加缓存标签

将静态变量替换为带缓存标签的数据获取函数,让缓存系统能追踪需要更新的内容:

'use server';

import ClientComp from './client_comp';
import { revalidateTag } from 'next/cache';

// 模拟数据存储(实际项目建议用数据库)
let textStore = 'initial text';

// 带缓存标签的数据获取函数
async function getText() {
  return textStore;
}

export async function updateText(newText: string) {
  textStore = newText;
  revalidateTag('text_update'); // 触发对应标签的内容重新验证
  return textStore;
}

export default async function ParentComp() {
  // 给数据请求打上标签,关联到revalidateTag的目标
  const text = await getText({ next: { tags: ['text_update'] } });
  return (
    <>
      <p style={{ color: 'green', backgroundColor: 'coral' }}>
         Received Text: {text}
      </p>
      <ClientComp />
    </>
  );
}

步骤2:客户端组件保持原有调用逻辑

客户端组件无需修改,正常调用服务端动作即可:

'use client';

import { updateText } from './parent_comp';

export default function ClientComp() {
 const handleClick = async () => {
  await updateText('devtz007');
};
return (
 <button
  onClick={handleClick}
  style={{ color: 'black', background: 'coral' }}
 >
  Send Text
 </button>
 );
}

关键说明

  • 必须给需要更新的服务端数据请求打上缓存标签,静态变量不会被缓存系统识别,无法通过revalidateTag()触发更新。
  • 这种方式只会重新渲染关联了对应标签的组件/数据,实现局部更新,不会触发整页刷新。
  • 跨页面场景下,只要其他页面的服务端组件使用了带text_update标签的getText()函数,点击ClientComp后这些页面的对应内容会自动更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 22:25:59