React Suspense 从入门到实战:让异步加载更优雅

二、代码分割场景

这是 Suspense 最成熟的应用场景,配合 React.lazy 实现组件懒加载。

javascript 复制代码
import { lazy, Suspense } from 'react';

const Dashboard = lazy(() => import('./Dashboard'));
const Settings = lazy(() => import('./Settings'));

function App() {
  return (
    <Suspense fallback={<PageLoader />}>
      <Routes>
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="/settings" element={<Settings />} />
      </Routes>
    </Suspense>
  );
}

多层 Suspense 边界:

javascript 复制代码
<Suspense fallback={<AppShell />}>
  <Layout>
    <Suspense fallback={<SidebarSkeleton />}>
      <Sidebar />
    </Suspense>
    <Suspense fallback={<ContentSkeleton />}>
      <Content />
    </Suspense>
  </Layout>
</Suspense>

三、数据请求场景

React 18 开始,Suspense 可以配合支持的数据请求库使用。

使用 SWR:

javascript 复制代码
import useSWR from 'swr';

function User({ id }) {
  const { data } = useSWR(`/api/user/${id}`, fetcher, {
    suspense: true  // 开启 Suspense 模式
  });
  
  return <div>{data.name}</div>;
}

<Suspense fallback={<UserSkeleton />}>
  <User id={123} />
</Suspense>

使用 React Query:

javascript 复制代码
import { useQuery } from '@tanstack/react-query';

function Posts() {
  const { data } = useQuery({
    queryKey: ['posts'],
    queryFn: fetchPosts,
    suspense: true
  });
  
  return data.map(post => <Post key={post.id} {...post} />);
}

四、与 Error Boundary 配合

Suspense 只处理"挂起"状态,错误需要 Error Boundary 捕获。

javascript 复制代码
class ErrorBoundary extends React.Component {
  state = { hasError: false };
  
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  
  render() {
    if (this.state.hasError) {
      return <ErrorFallback />;
    }
    return this.props.children;
  }
}

<ErrorBoundary>
  <Suspense fallback={<Loading />}>
    <DataComponent />
  </Suspense>
</ErrorBoundary>

五、与并发特性配合

配合 useTransition 避免不必要的 loading 状态:

javascript 复制代码
function SearchResults() {
  const [query, setQuery] = useState('');
  const [isPending, startTransition] = useTransition();
  
  const handleSearch = (value) => {
    startTransition(() => {
      setQuery(value);  // 低优先级更新
    });
  };
  
  return (
    <>
      <input onChange={e => handleSearch(e.target.value)} />
      {isPending && <InlineSpinner />}
      <Suspense fallback={<ResultsSkeleton />}>
        <Results query={query} />
      </Suspense>
    </>
  );
}

六、最佳实践

  1. 合理划分边界:按路由或功能模块设置 Suspense,避免过细或过粗
  2. 提供有意义的 fallback:使用骨架屏而非简单的 loading 文字
  3. 避免瀑布流:并行发起请求,而非串行等待
  4. 配合预加载:在用户交互前提前触发数据请求
javascript 复制代码
// 预加载示例
const resource = fetchUser(id);  // 提前发起

function Profile() {
  const user = use(resource);  // 直接使用
  return <div>{user.name}</div>;
}

七、注意事项

  • Suspense 在服务端渲染(SSR)中需要特殊处理,React 18 提供了流式 SSR 支持
  • 不是所有数据请求库都支持 Suspense,使用前查看文档
  • fallback 组件应该是轻量的,避免在其中执行副作用
  • 嵌套 Suspense 时,内层边界会优先生效

总结

Suspense 让异步操作的处理更加优雅和声明式。从代码分割到数据请求,它都能提供更好的开发体验和用户体验。配合 React 18 的并发特性,Suspense 将成为构建现代 React 应用的重要工具。

如果这篇文章对你有帮助,欢迎点赞收藏!

相关推荐
liangshanbo12152 分钟前
React useEffect 与 useLayoutEffect 面试题整理
前端·javascript·react.js
Bs_MoneyMagnet12 分钟前
基于springboot+vue的旅游景区点评系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring·旅游
ID346107442032 分钟前
【课程设计】基于Spring Boot+Vue的校园共享无人机服务系统设计与实现-计算机毕设 附源码44219
javascript·vue.js·spring boot·python·node.js·php·课程设计
夜不会漫长32 分钟前
C++:类和对象(2)
java·javascript·c++
IT毕设实战小研36 分钟前
基于大数据的国内主要农作物产量趋势分析与可视化
android·java·大数据·django·课程设计
星辞秋38 分钟前
Java 入门实战:从零搭建环境到写出第一个可用的命令行工具
java
ch.ju41 分钟前
Java—idea知识:如何创建新项目
java·开发语言·intellij-idea
土司大王43 分钟前
LeetCode hot100——74.搜索二维矩阵:Java 二分模板
java·算法·leetcode
BillKu1 小时前
Vue3 可拖拽分栏布局:两种实现方式详解
javascript·vue.js·ecmascript
2302_1111 小时前
java依赖小结
java·运维·数据库