refactor(ForecastReport): 架构优化与性能提升
阶段一 - 核心优化: - 所有子组件添加 React.memo 防止不必要重渲染 - 图表组件统一使用 EChartsWrapper 替代 ReactECharts - 提取 isForecastYear、IMPORTANT_METRICS 到 constants.ts - DetailTable 样式提取为 DETAIL_TABLE_STYLES 常量 阶段二 - 架构优化: - 新增 hooks/useForecastData.ts:数据获取 + Map 缓存 + AbortController - 新增 services/forecastService.ts:API 封装层 - 新增 utils/chartFormatters.ts:图表格式化工具函数 - 主组件精简:79行 → 63行,添加错误处理和重试功能 优化效果: - 消除 4 处 isForecastYear 重复定义 - 样式从每次渲染重建改为常量复用 - 添加请求缓存,避免频繁切换时重复请求 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
/**
|
||||
* 盈利预测报表视图 - 黑金主题
|
||||
* 优化:使用 useForecastData Hook、错误处理、memo 包装
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { Box, SimpleGrid } from '@chakra-ui/react';
|
||||
import { stockService } from '@services/eventService';
|
||||
import React, { memo } from 'react';
|
||||
import { Box, SimpleGrid, Center, VStack, Text, Button } from '@chakra-ui/react';
|
||||
import { useForecastData } from './hooks';
|
||||
import {
|
||||
IncomeProfitGrowthChart,
|
||||
EpsChart,
|
||||
@@ -12,68 +13,51 @@ import {
|
||||
DetailTable,
|
||||
} from './components';
|
||||
import LoadingState from '../LoadingState';
|
||||
import { CHART_HEIGHT } from './constants';
|
||||
import type { ForecastReportProps, ForecastData } from './types';
|
||||
import type { ForecastReportProps } from './types';
|
||||
|
||||
const ForecastReport: React.FC<ForecastReportProps> = ({ stockCode: propStockCode }) => {
|
||||
const [code, setCode] = useState(propStockCode || '600000');
|
||||
const [data, setData] = useState<ForecastData | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const ForecastReport: React.FC<ForecastReportProps> = ({ stockCode }) => {
|
||||
const { data, isLoading, error, refetch } = useForecastData(stockCode);
|
||||
|
||||
const load = useCallback(async () => {
|
||||
if (!code) return;
|
||||
setLoading(true);
|
||||
try {
|
||||
const resp = await stockService.getForecastReport(code);
|
||||
if (resp && resp.success) {
|
||||
setData(resp.data);
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [code]);
|
||||
// 加载状态
|
||||
if (isLoading && !data) {
|
||||
return <LoadingState message="加载盈利预测数据中..." height="300px" />;
|
||||
}
|
||||
|
||||
// 监听 props 中的 stockCode 变化
|
||||
useEffect(() => {
|
||||
if (propStockCode && propStockCode !== code) {
|
||||
setCode(propStockCode);
|
||||
}
|
||||
}, [propStockCode, code]);
|
||||
// 错误状态
|
||||
if (error && !data) {
|
||||
return (
|
||||
<Center h="200px">
|
||||
<VStack spacing={3}>
|
||||
<Text color="red.400">{error}</Text>
|
||||
<Button size="sm" colorScheme="yellow" variant="outline" onClick={refetch}>
|
||||
重试
|
||||
</Button>
|
||||
</VStack>
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
|
||||
// 加载数据
|
||||
useEffect(() => {
|
||||
if (code) {
|
||||
load();
|
||||
}
|
||||
}, [code, load]);
|
||||
// 无数据
|
||||
if (!data) return null;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
{/* 加载状态 */}
|
||||
{loading && !data && (
|
||||
<LoadingState message="加载盈利预测数据中..." height="300px" />
|
||||
)}
|
||||
|
||||
{/* 图表区域 - 3列布局 */}
|
||||
{data && (
|
||||
<SimpleGrid columns={{ base: 1, md: 3 }} spacing={4}>
|
||||
<IncomeProfitGrowthChart
|
||||
incomeProfitData={data.income_profit_trend}
|
||||
growthData={data.growth_bars}
|
||||
/>
|
||||
<EpsChart data={data.eps_trend} />
|
||||
<PePegChart data={data.pe_peg_axes} />
|
||||
</SimpleGrid>
|
||||
)}
|
||||
<SimpleGrid columns={{ base: 1, md: 3 }} spacing={4}>
|
||||
<IncomeProfitGrowthChart
|
||||
incomeProfitData={data.income_profit_trend}
|
||||
growthData={data.growth_bars}
|
||||
/>
|
||||
<EpsChart data={data.eps_trend} />
|
||||
<PePegChart data={data.pe_peg_axes} />
|
||||
</SimpleGrid>
|
||||
|
||||
{/* 详细数据表格 */}
|
||||
{data && (
|
||||
<Box mt={4}>
|
||||
<DetailTable data={data.detail_table} />
|
||||
</Box>
|
||||
)}
|
||||
<Box mt={4}>
|
||||
<DetailTable data={data.detail_table} />
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default ForecastReport;
|
||||
export default memo(ForecastReport);
|
||||
|
||||
Reference in New Issue
Block a user