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

React 18中Suspense的Fallback在数据获取时不生效怎么办?

问题原因

你的Suspense fallback不显示,核心原因是Suspense仅在组件抛出Promise时才会触发加载状态。而你当前用useEffect + useState的异步请求方式,组件会先完成初始渲染(此时users是空数组,渲染空列表),之后才在副作用里发起请求、更新状态重新渲染。整个过程组件没有抛出Promise,所以Suspense无法识别加载中的状态。

解决方案

下面提供两种React 18+兼容的实现方式,让Suspense能正确捕获加载状态:

方式一:使用React use 钩子

use是React 18引入的钩子,专门用于处理Promise类的资源。当Promise处于pending状态时,组件会自动抛出Promise,触发Suspense的fallback。

import React, { Suspense, use } from "react";

// 封装用户数据获取逻辑
const fetchUsers = async () => {
  const response = await fetch("https://jsonplaceholder.typicode.com/users");
  if (!response.ok) throw new Error("用户数据加载失败");
  return response.json();
};

function UsersList() {
  // use钩子会处理Promise,pending时触发Suspense fallback
  const users = use(fetchUsers());

  return (
    <div>
      <h4>获取到的用户详情如下:</h4>
      <ul>
        {users.map((user) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
}

function App() {
  return (
    <div className="App">
      <h2>用户列表</h2>
      <Suspense fallback={<h1>Loading...</h1>}>
        <UsersList />
      </Suspense>
    </div>
  );
}

export default App;

方式二:手动创建资源对象

如果不想使用use钩子,可以手动封装一个资源对象,让组件在数据未准备好时抛出Promise,触发Suspense。

import React, { Suspense } from "react";

// 创建资源工厂函数,处理异步数据的状态
function createResource(fetcher) {
  let status = "pending";
  let result;
  const promise = fetcher().then(
    (data) => {
      status = "success";
      result = data;
    },
    (error) => {
      status = "error";
      result = error;
    }
  );
  return {
    read() {
      if (status === "pending") throw promise;
      if (status === "error") throw result;
      return result;
    },
  };
}

// 初始化用户数据资源
const usersResource = createResource(() =>
  fetch("https://jsonplaceholder.typicode.com/users").then((res) => res.json())
);

function UsersList() {
  // 读取资源,未准备好时抛出Promise
  const users = usersResource.read();

  return (
    <div>
      <h4>获取到的用户详情如下:</h4>
      <ul>
        {users.map((user) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
}

function App() {
  return (
    <div className="App">
      <h2>用户列表</h2>
      <Suspense fallback={<h1>Loading...</h1>}>
        <UsersList />
      </Suspense>
    </div>
  );
}

export default App;
额外注意点
  • 不要把不需要等待的元素(比如原代码中的<h4>)放在Suspense包裹范围内,否则这些元素会直接渲染,破坏加载状态的统一性。建议把相关内容都放到需要等待数据的组件中。
  • 测试时可以通过Chrome开发者工具限制网络速度(比如设置为Slow 3G),就能看到明显的Loading状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 06:10:33