在服务端渲染(SSR)应用中,错误处理是保障用户体验的关键环节。本文将分享一个实际的Hook重构方案,用于处理SSR环境下的异步数据获取错误。
问题场景 在我们的电商应用中,首页需要同时加载商品列表和banner信息。由于SSR环境下服务端需要预加载数据,一旦某个API调用失败,整个页面渲染会中断。原始实现中,我们使用了基础的useEffect配合useState来处理错误状态,但存在以下问题:
- 错误边界无法捕获服务端渲染时的异步错误
- 服务端和客户端的错误处理逻辑不一致
- 缺乏统一的错误恢复机制
重构方案 我们创建了一个自定义Hook useSSRDataError,该Hook封装了完整的错误处理逻辑:
const useSSRDataError = (asyncFn, deps = []) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
// 服务端渲染错误处理
if (typeof window === 'undefined') {
asyncFn()
.then(result => {
setData(result);
setLoading(false);
})
.catch(err => {
// 服务端记录错误但不中断渲染
console.error('SSR Error:', err);
setError(err);
setLoading(false);
});
} else {
// 客户端错误处理
asyncFn()
.then(result => {
setData(result);
setLoading(false);
})
.catch(err => {
setError(err);
setLoading(false);
// 客户端可触发错误边界或显示友好提示
});
}
}, deps);
const retry = useCallback(() => {
setLoading(true);
setError(null);
asyncFn().then(setData).catch(setError);
}, [asyncFn]);
return { data, loading, error, retry };
};
实际应用示例 在商品列表组件中:
const ProductList = () => {
const { data, loading, error, retry } = useSSRDataError(
() => fetchProducts(),
[]
);
if (loading) return <LoadingSpinner />;
if (error) return (
<ErrorBoundary fallback={<RetryButton onRetry={retry} />}>
<ErrorMessage message="商品加载失败" />
</ErrorBoundary>
);
return <ProductGrid products={data} />;
};
通过该Hook重构,我们实现了服务端渲染错误的优雅降级,确保了应用在任何环境下都能提供稳定的用户体验。

讨论