perf(HotspotOverview): 日期切换时只刷新图表,不重新渲染整个模块

- useHotspotData 新增 refreshing 状态,区分首次加载和切换日期
- 首次加载显示全屏 loading,切换日期仅显示图表区域加载指示器
- 避免日期切换时整体布局闪烁

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-12-31 14:43:44 +08:00
parent 494d9c8918
commit df3d502862

View File

@@ -11,13 +11,18 @@ import { getApiBase } from '@utils/apiConfig';
* @returns {Object} 数据和状态 * @returns {Object} 数据和状态
*/ */
export const useHotspotData = (selectedDate) => { export const useHotspotData = (selectedDate) => {
// 首次加载状态(仅在初始化时为 true
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
// 刷新状态(切换日期时为 true不影响整体布局
const [refreshing, setRefreshing] = useState(false);
const [error, setError] = useState(null); const [error, setError] = useState(null);
const [data, setData] = useState(null); const [data, setData] = useState(null);
// 用于防止 React StrictMode 下的双重请求 // 用于防止 React StrictMode 下的双重请求
const fetchingRef = useRef(false); const fetchingRef = useRef(false);
const lastDateRef = useRef(null); const lastDateRef = useRef(null);
// 是否已完成首次加载
const initializedRef = useRef(false);
const fetchData = useCallback(async (forceRefetch = false) => { const fetchData = useCallback(async (forceRefetch = false) => {
// 获取日期字符串用于比较 // 获取日期字符串用于比较
@@ -29,14 +34,20 @@ export const useHotspotData = (selectedDate) => {
} }
// 如果日期未变化且已有数据,跳过(除非是强制刷新) // 如果日期未变化且已有数据,跳过(除非是强制刷新)
if (lastDateRef.current === dateStr && !forceRefetch) { if (lastDateRef.current === dateStr && data && !forceRefetch) {
return; return;
} }
fetchingRef.current = true; fetchingRef.current = true;
setLoading(true);
setError(null); setError(null);
// 区分首次加载和后续刷新
if (!initializedRef.current) {
setLoading(true);
} else {
setRefreshing(true);
}
try { try {
const dateParam = selectedDate const dateParam = selectedDate
? `?date=${dateStr}` ? `?date=${dateStr}`
@@ -47,6 +58,7 @@ export const useHotspotData = (selectedDate) => {
if (result.success) { if (result.success) {
setData(result.data); setData(result.data);
lastDateRef.current = dateStr; lastDateRef.current = dateStr;
initializedRef.current = true;
} else { } else {
setError(result.error || '获取数据失败'); setError(result.error || '获取数据失败');
} }
@@ -55,16 +67,18 @@ export const useHotspotData = (selectedDate) => {
setError('网络请求失败'); setError('网络请求失败');
} finally { } finally {
setLoading(false); setLoading(false);
setRefreshing(false);
fetchingRef.current = false; fetchingRef.current = false;
} }
}, [selectedDate]); // 移除 data 依赖,避免循环更新 }, [selectedDate, data]);
useEffect(() => { useEffect(() => {
fetchData(); fetchData();
}, [fetchData]); }, [fetchData]);
return { return {
loading, loading, // 首次加载状态
refreshing, // 切换日期刷新状态
error, error,
data, data,
refetch: () => fetchData(true), refetch: () => fetchData(true),