Files
vf_react/src/views/Company/components/CompanyOverview/hooks/useShareholderData.ts
zdl 77ea38e5c9 perf(hooks): 使用 useRef 缓存加载状态,避免 Tab 切换重复请求
- 使用 useRef 替代 useState 跟踪 hasLoaded 状态
- Tab 切换回来时保持数据缓存,不重新发起请求
- stockCode 变化时重置加载状态,确保新股票正常加载
- useAnnouncementsData 支持 refreshKey 强制刷新

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-22 13:04:55 +08:00

121 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/views/Company/components/CompanyOverview/hooks/useShareholderData.ts
// 股权结构数据 Hook - 用于股权结构 Tab
import { useState, useEffect, useRef } from "react";
import { logger } from "@utils/logger";
import axios from "@utils/axiosConfig";
import type { ActualControl, Concentration, Shareholder } from "../types";
interface ApiResponse<T> {
success: boolean;
data: T;
}
// 支持延迟加载的配置选项
interface UseShareholderDataOptions {
stockCode?: string;
/** 是否启用数据加载,默认 true */
enabled?: boolean;
}
interface UseShareholderDataResult {
actualControl: ActualControl[];
concentration: Concentration[];
topShareholders: Shareholder[];
topCirculationShareholders: Shareholder[];
loading: boolean;
error: string | null;
}
/**
* 股权结构数据 Hook支持延迟加载
* @param options - 配置选项
* @param options.stockCode - 股票代码
* @param options.enabled - 是否启用数据加载,默认 true
*/
export const useShareholderData = (options: UseShareholderDataOptions): UseShareholderDataResult => {
const { stockCode, enabled = true } = options;
const [actualControl, setActualControl] = useState<ActualControl[]>([]);
const [concentration, setConcentration] = useState<Concentration[]>([]);
const [topShareholders, setTopShareholders] = useState<Shareholder[]>([]);
const [topCirculationShareholders, setTopCirculationShareholders] = useState<Shareholder[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
// 使用 ref 跟踪是否已加载,避免 Tab 切换时重复请求
const hasLoadedRef = useRef(false);
// 记录上次加载的 stockCodestockCode 变化时需要重新加载
const lastStockCodeRef = useRef<string | undefined>(undefined);
useEffect(() => {
// 只有 enabled 且有 stockCode 时才请求
if (!enabled || !stockCode) {
setLoading(false);
return;
}
// stockCode 变化时重置加载状态
if (lastStockCodeRef.current !== stockCode) {
hasLoadedRef.current = false;
lastStockCodeRef.current = stockCode;
}
// 如果已经加载过数据不再重新请求Tab 切换回来时保持缓存)
if (hasLoadedRef.current) {
setLoading(false);
return;
}
const controller = new AbortController();
const loadData = async () => {
setLoading(true);
setError(null);
try {
const [
{ data: actualRes },
{ data: concentrationRes },
{ data: shareholdersRes },
{ data: circulationRes },
] = await Promise.all([
axios.get<ApiResponse<ActualControl[]>>(`/api/stock/${stockCode}/actual-control`, { signal: controller.signal }),
axios.get<ApiResponse<Concentration[]>>(`/api/stock/${stockCode}/concentration`, { signal: controller.signal }),
axios.get<ApiResponse<Shareholder[]>>(`/api/stock/${stockCode}/top-shareholders?limit=10`, { signal: controller.signal }),
axios.get<ApiResponse<Shareholder[]>>(`/api/stock/${stockCode}/top-circulation-shareholders?limit=10`, { signal: controller.signal }),
]);
if (actualRes.success) setActualControl(actualRes.data);
if (concentrationRes.success) setConcentration(concentrationRes.data);
if (shareholdersRes.success) setTopShareholders(shareholdersRes.data);
if (circulationRes.success) setTopCirculationShareholders(circulationRes.data);
setLoading(false);
hasLoadedRef.current = true;
} catch (err: any) {
// 请求被取消时,不更新任何状态
if (err.name === "CanceledError") {
return;
}
logger.error("useShareholderData", "loadData", err, { stockCode });
setError("加载股权结构数据失败");
setLoading(false);
hasLoadedRef.current = true;
}
};
loadData();
return () => controller.abort();
}, [stockCode, enabled]);
const isLoading = loading || (enabled && !hasLoadedRef.current && !error);
return {
actualControl,
concentration,
topShareholders,
topCirculationShareholders,
loading: isLoading,
error,
};
};