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

Next13服务端组件如何基于动态chainId获取并刷新数据?

可行方案推荐

针对你在Next.js 13 App Router中遇到的服务端组件无法获取客户端Context中chainId的问题,这里有三种实用方案,都能保持LottosPage为服务端组件,同时实现切换chainId时自动重新获取数据:


方案1:将chainId作为URL搜索参数(最简便)

把chainId存在URL的查询参数里,服务端组件可以直接通过searchParams props获取,切换时自动触发服务端组件重新渲染。

步骤:

  1. 客户端下拉框组件(需标记'use client')
'use client';

import { useRouter, useSearchParams } from 'next/navigation';

export default function ChainSelector() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const currentChainId = searchParams.get('chainId') || '1'; // 设置默认chainId

  const handleChainChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
    const newChainId = e.target.value;
    // 更新URL的查询参数,自动触发服务端组件重新获取数据
    router.push({
      searchParams: { chainId: newChainId },
    });
  };

  return (
    <select value={currentChainId} onChange={handleChainChange}>
      <option value="1">Ethereum</option>
      <option value="5">Goerli</option>
      <option value="137">Polygon</option>
    </select>
  );
}
  1. 服务端组件LottosPage
// 无需标记'use client',天然是服务端组件
export default async function LottosPage({
  searchParams,
}: {
  searchParams: { chainId?: string };
}) {
  const chainId = searchParams.chainId || '1';
  // 基于chainId请求数据
  const lottoData = await fetch(`https://your-api.com/lottos?chainId=${chainId}`).then(res => res.json());

  return (
    <div>
      <h1>Chain {chainId} 彩票列表</h1>
      <ul>
        {lottoData.map((lotto: any) => (
          <li key={lotto.id}>{lotto.name}</li>
        ))}
      </ul>
    </div>
  );
}
  1. 在layout.tsx中引入下拉框
    直接把ChainSelector放在导航栏或页面顶部即可,无需额外处理。

方案2:将chainId存在Cookie中

把chainId存储到Cookie里,服务端组件通过next/headers的cookies()函数读取,切换时刷新路由触发重新获取。

步骤:

  1. 客户端下拉框组件
'use client';

import { useRouter, cookies } from 'next/navigation';

export default function ChainSelector() {
  const router = useRouter();
  const cookieStore = cookies();
  const currentChainId = cookieStore.get('chainId')?.value || '1';

  const handleChainChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
    const newChainId = e.target.value;
    // 设置Cookie
    cookieStore.set('chainId', newChainId, { path: '/' });
    // 刷新路由让服务端组件读取新Cookie
    router.refresh();
  };

  return (
    <select value={currentChainId} onChange={handleChainChange}>
      <option value="1">Ethereum</option>
      <option value="5">Goerli</option>
      <option value="137">Polygon</option>
    </select>
  );
}
  1. 服务端组件LottosPage
import { cookies } from 'next/headers';

export default async function LottosPage() {
  const chainId = cookies().get('chainId')?.value || '1';
  const lottoData = await fetch(`https://your-api.com/lottos?chainId=${chainId}`).then(res => res.json());

  return (
    <div>
      <h1>Chain {chainId} 彩票列表</h1>
      <ul>
        {lottoData.map((lotto: any) => (
          <li key={lotto.id}>{lotto.name}</li>
        ))}
      </ul>
    </div>
  );
}

方案3:使用动态路由段(语义化更强)

把chainId作为路由的一部分(如/lottos/[chainId]),服务端组件通过params props获取,适合需要URL语义化的场景。

步骤:

  1. 创建动态路由页面
    在app/lottos/[chainId]/page.tsx中编写服务端组件:
export default async function LottosPage({ params }: { params: { chainId: string } }) {
  const chainId = params.chainId;
  const lottoData = await fetch(`https://your-api.com/lottos?chainId=${chainId}`).then(res => res.json());

  return (
    <div>
      <h1>Chain {chainId} 彩票列表</h1>
      <ul>
        {lottoData.map((lotto: any) => (
          <li key={lotto.id}>{lotto.name}</li>
        ))}
      </ul>
    </div>
  );
}
  1. 客户端下拉框组件
'use client';

import { useRouter, usePathname } from 'next/navigation';

export default function ChainSelector() {
  const router = useRouter();
  const pathname = usePathname();
  const currentChainId = pathname.split('/')[2] || '1';

  const handleChainChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
    const newChainId = e.target.value;
    router.push(`/lottos/${newChainId}`);
  };

  return (
    <select value={currentChainId} onChange={handleChainChange}>
      <option value="1">Ethereum</option>
      <option value="5">Goerli</option>
      <option value="137">Polygon</option>
    </select>
  );
}

方案选择建议

  • 如果你只是临时切换chainId获取数据,**方案1(搜索参数)**最简便,无需修改路由结构,刷新页面状态也能保留。
  • 如果你需要持久化用户的chainId选择(下次打开页面自动加载),**方案2(Cookie)**更合适。
  • 如果你希望URL语义化更强,把chainId作为资源标识,**方案3(动态路由)**是更好的选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 16:52:57