React Query 支持与 React Suspense 集成,使得数据获取可以像处理组件渲染一样自然:
基本集成方法
-
启用 Suspense 模式:
javascriptconst { data } = useQuery('todos', fetchTodos, { suspense: true, }); -
使用 Suspense 组件包裹:
javascriptfunction TodoList() { const { data: todos } = useQuery('todos', fetchTodos, { suspense: true, }); return ( <ul> {todos.map(todo => ( <li key={todo.id}>{todo.title}</li> ))} </ul> ); } function App() { return ( <Suspense fallback={<div>Loading...</div>}> <TodoList /> </Suspense> ); }
错误边界处理
当使用 Suspense 模式时,错误需要通过 Error Boundary 捕获:
javascriptclass ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false, error: null }; } static getDerivedStateFromError(error) { return { hasError: true, error }; } render() { if (this.state.hasError) { return <div>Error: {this.state.error.message}</div>; } return this.props.children; } } function App() { return ( <ErrorBoundary> <Suspense fallback={<div>Loading...</div>}> <TodoList /> </Suspense> </ErrorBoundary> ); }
注意事项
-
兼容性:
- Suspense 模式需要 React 16.6+ 版本
- 确保所有相关组件都支持 Suspense
-
错误处理:
- 必须使用 Error Boundary 捕获错误
- 不能再使用 useQuery 返回的 error 和 isError 属性
-
缓存行为:
- 即使数据在缓存中,首次渲染时仍会触发 Suspense
- 后续渲染会直接使用缓存数据,不会触发 Suspense
-
性能考虑:
- Suspense 模式可能会导致组件树的多次渲染
- 对于复杂应用,需要权衡用户体验和性能
-
与其他功能的兼容性:
- 窗口聚焦重新获取:可能会导致意外的 Suspense 触发
- 轮询:需要谨慎配置,避免频繁触发 Suspense
-
服务器端渲染:
- 在 SSR 环境中使用 Suspense 需要特殊处理
- 推荐使用
dehydrate和hydrate方法
最佳实践
-
渐进式采用:
- 先在非关键组件中尝试 Suspense 模式
- 逐步扩展到整个应用
-
合理使用 fallback:
- 提供有意义的加载状态
- 避免使用过于简单的加载指示器
-
结合预取:
- 使用
queryClient.prefetchQuery提前获取数据 - 减少 Suspense 的触发次数
- 使用
-
错误边界策略:
- 在适当的层级放置 Error Boundary
- 提供具体的错误信息和恢复选项
通过合理集成 React Query 和 Suspense,可以创建更加流畅、响应迅速的用户界面,同时保持代码的简洁性和可读性。