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:
@@ -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),
|
||||||
|
|||||||
Reference in New Issue
Block a user