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

NextJS 13.4.13服务器组件如何使用Zustand状态值?

解决方案:Next.js 13服务器组件中使用Zustand状态获取数据

方案一:拆分组件,客户端组件处理状态与数据请求

核心思路是保留Home作为服务器组件,将依赖Zustand状态的数据请求逻辑拆分到独立的客户端组件中,用SWR/React Query这类数据请求库处理异步逻辑(也可原生实现)。

步骤1:创建客户端组件CountryData.js

'use client';

import useStore from "@/utils/store";
import useSWR from 'swr';

// 复用数据请求函数
const fetcher = async (locale) => {
  const res = await fetch(`localhost:3001/api/${locale}`);
  if (!res.ok) throw new Error('Failed to fetch data');
  return res.json();
};

export default function CountryData() {
  // 从Zustand获取状态
  const countryCode = useStore((state) => state.countryCode);
  // 用SWR根据countryCode自动发起请求
  const { data, error, isLoading } = useSWR(countryCode ? countryCode : null, fetcher);

  if (isLoading) return <div>加载中...</div>;
  if (error) return <div>错误:{error.message}</div>;

  return <MyComponent data={data} />;
}

步骤2:修改page.js的Home组件

const Home = () => {
  return (
    <main className='margin'>
      {/* 渲染客户端组件 */}
      <CountryData />
    </main>
  );
};

export default Home;

Home依然是服务器组件,无需async,数据请求和状态依赖逻辑完全交给客户端组件处理。

方案二:通过URL参数传递状态,服务器组件直接获取

如果需要状态与URL同步(支持分享链接),可将选择的国家代码放到URL查询参数中,服务器组件从searchParams读取后发起请求。

步骤1:修改page.js的Home组件

import { Suspense } from 'react';

const getData = async (locale) => {
  const res = await fetch(`localhost:3001/api/${locale}`);
  if (!res.ok) throw new Error('Failed to fetch data');
  return res.json();
};

// 抽离异步逻辑到子组件,用Suspense处理加载状态
async function DataComponent({ searchParams }) {
  // 从URL参数拿国家代码,默认用AU
  const countryCode = searchParams.country || 'AU';
  const data = await getData(countryCode);
  return <MyComponent data={data} />;
}

const Home = () => {
  return (
    <main className='margin'>
      <Suspense fallback={<div>加载中...</div>}>
        <DataComponent />
      </Suspense>
    </main>
  );
};

export default Home;

步骤2:修改下拉选择组件(客户端组件)

'use client';

import useStore from "@/utils/store";
import { useRouter, useSearchParams } from 'next/navigation';

export default function CountrySelector() {
  const setCountryCode = useStore((state) => state.setCountryCode);
  const router = useRouter();
  const searchParams = useSearchParams();

  const handleChange = (e) => {
    const selectedCode = e.target.value;
    // 更新Zustand状态
    setCountryCode(selectedCode);
    // 更新URL参数,触发服务器组件重新渲染
    const newSearchParams = new URLSearchParams(searchParams);
    newSearchParams.set('country', selectedCode);
    router.push(`/?${newSearchParams.toString()}`);
  };

  return (
    <select onChange={handleChange}>
      <option value="AU">澳大利亚</option>
      <option value="US">美国</option>
      {/* 其他国家选项 */}
    </select>
  );
}

这种方案下,服务器组件可正常使用async发起请求,同时URL会同步当前选择的国家代码,状态一致性更好。

方案三:客户端组件用useEffect处理请求(无第三方库)

如果不想引入SWR/React Query,也可以用React原生的useEffect监听Zustand状态变化,触发数据请求:

'use client';

import useStore from "@/utils/store";
import { useState, useEffect } from 'react';

const getData = async (locale) => {
  const res = await fetch(`localhost:3001/api/${locale}`);
  if (!res.ok) throw new Error('Failed to fetch data');
  return res.json();
};

export default function CountryData() {
  const countryCode = useStore((state) => state.countryCode);
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      try {
        const result = await getData(countryCode);
        setData(result);
        setError(null);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    // 当countryCode存在时发起请求
    if (countryCode) fetchData();
  }, [countryCode]);

  if (loading) return <div>加载中...</div>;
  if (error) return <div>错误:{error}</div>;
  if (!data) return <div>暂无数据</div>;

  return <MyComponent data={data} />;
}

同样,Home组件只需渲染这个客户端组件即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 21:15:55