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

Next.js 14中cookies().set()触发页面刷新及TRPC请求异常问题

问题

1. Next.js 14中调用cookies().set()是否会触发整页刷新?

在图表组件切换时间间隔时,原本仅重新获取数据无异常,但现在触发整页刷新,导致同路由内的高负载组件也随之重载。官方文档仅说明:

Using it in a layout or page will opt a route into dynamic rendering at request time.
但这不应该意味着调用该方法会触发整页刷新,对吗?

2. TRPC请求失败问题

网络面板中所有后端请求均出现获取响应失败的情况,带有cookies()调用的组件的请求负载包含设置的cookie值或Next.js生成的乱码内容,示例如下:

1: "tkJNa2edO1ReSBFeTtF3/ylWv+2A46cEY5LLkcOCkYgMnfkWeX/SMd+/CCIPBH4W9IettDZ1H0IM9xHzjjKJ4w28FevcMDLnMkHF0H7TymCoxFH04w=="
2_$ACTION_REF_1: 
2_$ACTION_1:1: ["$@2"]
2_$ACTION_1:0: {"id":"8ad85c6f04f4b5912851a1a1b7731332e1b2753c","bound":"$@1"}
2_$ACTION_1:2: "tWfv6x4N8OQpm2utvGMwGwQAHv8WRKnPZYXCJEXaI224Bve7D+IVjbkA9F+v9u5hdU2xmwNmx8usNLY5DsewZqmpDRXD1X7vzsM33CUZSs8wsg9DVA=="
0: ["$@1","$K2"]

相关代码

TradingCharts组件

export async function TradingCharts({ symbol }: D3ChartProps) {
  const interval = (cookies().get('interval')?.value ?? '1d') as KlineInterval;
  const candlesticksPromise = client.binance.candlestick.query({
    symbol,
    interval,
  });
  const lastTradePromise = client.binance.lastTrade.query({ symbol });
  const [candlesticks, recentTrade] = await Promise.all([candlesticksPromise, lastTradePromise]);

  const handleIntervalChange = async (interval: KlineInterval) => {
    'use server';
    cookies().set('interval', interval, { maxAge: 0 });
  };

  return (
    <section className={styles.container}>
      <IntervalButtons changeInterval={handleIntervalChange} currentInterval={interval} />
      <CandlestickChart
        {...{ symbol, candlesticks, interval, recentTrade: parseFloat(recentTrade ?? '0') }}
        key={interval}
      />
    </section>
  );
}

TRPC客户端初始化代码

export const client = createTRPCProxyClient<AppRouter>({
  links: [
    splitLink({
      condition: (op) => op.type === 'subscription',
      true: wsLink({
        client: createWSClient({
          url: 'ws://localhost:7000',
        }),
      }),
      false: httpBatchLink({
        url: 'http://localhost:7000',
        fetch(url, options) {
          return fetch(url, {
            ...options,
            credentials: 'include',
            cache: 'no-store',
          });
        },
      }),
    }),
  ],
});

解答

关于cookies().set()触发整页刷新的问题

你当前的handleIntervalChange是Server Action(因为标注了'use server'),Next.js 13+中Server Action默认执行后会触发整页重新渲染——这是Server Action的特性,和cookies().set()本身无关。

要避免整页刷新,推荐两种方案:

  1. 改用客户端操作Cookie:将按钮逻辑抽离为客户端组件,用document.cookie设置Cookie后,调用router.refresh()局部刷新服务端组件(不会触发整页重载)。示例:

    'use client';
    import { useRouter } from 'next/navigation';
    
    export function IntervalButtonsClient({ currentInterval }: { currentInterval: KlineInterval }) {
      const router = useRouter();
      const handleIntervalChange = (interval: KlineInterval) => {
        document.cookie = `interval=${interval}; path=/; max-age=0`;
        router.refresh();
      };
      return <IntervalButtons changeInterval={handleIntervalChange} currentInterval={currentInterval} />;
    }
    

    之后在TradingCharts组件中替换为这个客户端组件即可。

  2. 配置Server Action无刷新更新:使用Next.js的experimental_useOptimistic配合状态管理实现无刷新,但复杂度较高,不如第一种方案直接。

关于TRPC请求失败的问题

你看到的乱码负载是Next.js Server Action的内部序列化格式,原因是TradingCharts作为服务端组件,直接调用了客户端TRPC实例——TRPC的httpBatchLink默认在客户端环境发送请求,在服务端组件中调用会被转发为Server Action的内部请求,导致格式异常。

解决方法:

  1. 服务端直接调用TRPC Procedure:如果TRPC路由和前端同项目,可在服务端组件中直接调用后端的Procedure函数,无需通过客户端实例。示例:

    import { appRouter } from '@/server/api/root';
    import { createTRPCContext } from '@/server/api/trpc';
    
    // 在TradingCharts组件中
    const ctx = await createTRPCContext({});
    const candlesticks = await appRouter.binance.candlestick.query({ symbol, interval }, ctx);
    const recentTrade = await appRouter.binance.lastTrade.query({ symbol }, ctx);
    
  2. 将TRPC调用移到客户端组件:给TradingCharts添加'use client'标记转为客户端组件,此时TRPC的httpBatchLink会正常发送客户端请求,不会被Server Action干扰,同时配合客户端Cookie操作避免整页刷新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 21:54:53