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

Next.js项目中使用useSWR请求Firebase实时数据库时data与error均返回null的问题

Next.js中使用useSWR请求Firebase实时数据库时data和error始终为null

我在Next.js项目中尝试使用useSWR请求Firebase实时数据库,但不知为何data和error变量始终返回null。相关代码如下:

import useSWR from 'swr';
const LastSales: NextPage = () => {
  const [sales, setSales] = useState<Sale[]>([]);
  const { data, error } = useSWR(
    'https://my-app-12345-default-rtdb.firebaseio.com/sales.json'
  );

  useEffect(() => {
    if (!data) return;
    const salesArr = [];
    for (const key in data) {
      salesArr.push({
        id: key,
        username: data[key].username,
        volume: data[key].volume,
      });
    }
    setSales(salesArr);
  }, [data]);

  if (error) return <p>Failed to load.</p>;
  if (sales.length === 0) return <p>Loading...</p>;
  return <div>Sales List</div>

使用fetch发起相同请求时完全正常,但代码量是useSWR方式的10倍。请问为何data和error都会等于null?


可能的原因及解决方案

1. 未显式指定fetcher函数(最常见原因)

虽然useSWR自带默认的fetcher,但它的逻辑比较简单(仅调用fetch(url).then(res => res.json())),没有处理HTTP错误状态码(比如4xx/5xx),也可能在某些环境下无法正确解析Firebase的响应。当请求出现异常时,默认fetcher可能不会正确抛出错误,导致data和error都处于null状态。

解决方法:手动定义一个带错误处理的fetcher,并传递给useSWR:

// 定义自定义fetcher
const fetcher = async (url: string) => {
  const res = await fetch(url);
  // 检查响应状态
  if (!res.ok) {
    throw new Error(`请求失败: ${res.status}`);
  }
  return res.json();
};

// 在useSWR中使用该fetcher
const { data, error } = useSWR(
  'https://my-app-12345-default-rtdb.firebaseio.com/sales.json',
  fetcher
);

2. Next.js渲染模式导致客户端请求未触发

useSWR是客户端优先的数据获取库,默认情况下在服务器端渲染(SSR)或静态生成(SSG)阶段不会发起请求。如果你的页面是SSR/SSG模式,初始渲染时data会保持null,直到客户端hydration完成后才会发起请求。

解决方法:

  • 调整加载状态的判断逻辑,直接基于data和error判断,而不是依赖衍生的sales状态:
    if (error) return <p>Failed to load.</p>;
    if (!data) return <p>Loading...</p>; // 直接检查data是否存在
    
  • 如果需要在服务器端预获取数据,可以结合Next.js的getServerSideProps或getStaticProps,再将数据传递给组件,同时用useSWR做客户端的重新验证。

3. Firebase安全规则或认证问题

虽然你提到fetch请求正常,但需要确认useSWR的请求是否携带了必要的认证信息(如果你的Firebase数据库要求认证)。默认情况下,useSWR的fetcher不会自动携带认证凭证,而你手动写的fetch可能已经处理了认证。

解决方法:如果数据库需要认证,在fetcher中添加认证头:

import { getAuth } from 'firebase/auth';

const fetcher = async (url: string) => {
  const auth = getAuth();
  const idToken = await auth.currentUser?.getIdToken();
  
  const res = await fetch(url, {
    headers: idToken ? { Authorization: `Bearer ${idToken}` } : {}
  });
  
  if (!res.ok) throw new Error('请求失败');
  return res.json();
};

4. useSWR版本问题

旧版本的useSWR可能存在一些兼容性bug,导致请求无法正常触发。建议更新到最新版本:

npm install swr@latest
# 或
yarn add swr@latest

简化代码的建议

你可以直接基于useSWR返回的data转换为sales数组,无需额外的useState和useEffect,让代码更简洁:

import useSWR from 'swr';

const LastSales: NextPage = () => {
  const fetcher = async (url: string) => {
    const res = await fetch(url);
    if (!res.ok) throw new Error('Failed to load sales');
    return res.json();
  };

  const { data, error } = useSWR(
    'https://my-app-12345-default-rtdb.firebaseio.com/sales.json',
    fetcher
  );

  if (error) return <p>Failed to load.</p>;
  if (!data) return <p>Loading...</p>;

  // 直接转换data为sales数组
  const sales = Object.entries(data).map(([key, value]) => ({
    id: key,
    username: value.username,
    volume: value.volume
  }));

  return <div>Sales List: {sales.length} items</div>;
};

export default LastSales;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 15:37:41