服务端渲染数据同步Hook踩坑记录
最近在重构一个SSR应用时,遇到了一个经典的React Hook使用陷阱。项目中有个用户信息组件需要在服务端获取数据并在客户端进行同步,原本的实现方式导致了严重的hydration mismatch问题。
问题复现步骤
- 创建了一个useUserData hook,在服务端通过API获取用户数据
- 客户端初始化时直接使用服务器返回的数据
- 在组件中使用
useEffect进行数据更新 - 浏览器控制台出现大量hydration warning
原始错误实现
const useUserData = (userId) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// 服务端渲染时,这个effect不会执行
fetchUser(userId).then(setData);
}, [userId]);
return { data, loading };
};
踩坑后的重构方案
最终采用了一个更加健壮的SSR数据同步策略:
const useUserData = (userId, serverData) => {
const [data, setData] = useState(serverData || null);
const [loading, setLoading] = useState(!serverData);
useEffect(() => {
// 只有在客户端且数据为空时才重新获取
if (!serverData && typeof window !== 'undefined') {
fetchUser(userId).then((userData) => {
setData(userData);
setLoading(false);
});
}
}, [userId, serverData]);
return { data, loading };
};
关键优化点
- 服务端传递初始数据避免重复请求
- 客户端环境判断避免hydration冲突
- 使用loading状态处理不同场景
- 组件内使用useMemo缓存计算结果
这个重构方案有效解决了SSR场景下的数据同步问题,避免了客户端和服务端渲染内容不一致的错误。

讨论