From 8c9cc9845d264496d7cc54bf49c6898a2d753128 Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Fri, 19 Dec 2025 17:10:39 +0800 Subject: [PATCH] =?UTF-8?q?perf(DynamicTracking):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E5=8A=A0=E8=BD=BD=E4=BD=93=E9=AA=8C=EF=BC=8C?= =?UTF-8?q?=E5=AD=90=E7=BB=84=E4=BB=B6=E6=87=92=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 使用 React.lazy() 懒加载所有子面板组件 - 为每个 Tab 添加专属骨架屏 fallback - SubTabContainer 同步渲染,点击立即显示二级导航 - 添加 memo、useCallback、useMemo 性能优化 - 新增 DynamicTrackingSkeleton.tsx 骨架屏组件 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../components/DynamicTrackingSkeleton.tsx | 101 ++++++++++++++++++ .../DynamicTracking/components/index.js | 9 ++ .../components/DynamicTracking/index.js | 77 ++++++++++--- 3 files changed, 170 insertions(+), 17 deletions(-) create mode 100644 src/views/Company/components/DynamicTracking/components/DynamicTrackingSkeleton.tsx diff --git a/src/views/Company/components/DynamicTracking/components/DynamicTrackingSkeleton.tsx b/src/views/Company/components/DynamicTracking/components/DynamicTrackingSkeleton.tsx new file mode 100644 index 00000000..335b0bba --- /dev/null +++ b/src/views/Company/components/DynamicTracking/components/DynamicTrackingSkeleton.tsx @@ -0,0 +1,101 @@ +/** + * 动态跟踪 Tab 骨架屏组件 + * 用于懒加载时显示,提供即时反馈 + */ + +import React from 'react'; +import { Box, VStack, HStack, Skeleton, SkeletonText, Card, CardBody } from '@chakra-ui/react'; + +/** + * 新闻动态骨架屏 + */ +export const NewsPanelSkeleton: React.FC = () => ( + + {[1, 2, 3, 4, 5].map((i) => ( + + + + + + + + + + + + ))} + +); + +/** + * 公告列表骨架屏 + */ +export const AnnouncementsSkeleton: React.FC = () => ( + + {[1, 2, 3, 4].map((i) => ( + + + + + + + + + + + + ))} + +); + +/** + * 财报披露日程骨架屏 + */ +export const DisclosureScheduleSkeleton: React.FC = () => ( + + + + {[1, 2, 3].map((i) => ( + + + + + ))} + + +); + +/** + * 业绩预告骨架屏 + */ +export const ForecastPanelSkeleton: React.FC = () => ( + + + + + + + + + + + + +); + +/** + * 通用内容骨架屏(默认 fallback) + */ +export const ContentSkeleton: React.FC = () => ( + + + +); + +export default { + NewsPanelSkeleton, + AnnouncementsSkeleton, + DisclosureScheduleSkeleton, + ForecastPanelSkeleton, + ContentSkeleton, +}; diff --git a/src/views/Company/components/DynamicTracking/components/index.js b/src/views/Company/components/DynamicTracking/components/index.js index 44bc24a1..5c37b1bd 100644 --- a/src/views/Company/components/DynamicTracking/components/index.js +++ b/src/views/Company/components/DynamicTracking/components/index.js @@ -2,3 +2,12 @@ export { default as NewsPanel } from './NewsPanel'; export { default as ForecastPanel } from './ForecastPanel'; + +// 骨架屏组件 +export { + NewsPanelSkeleton, + AnnouncementsSkeleton, + DisclosureScheduleSkeleton, + ForecastPanelSkeleton, + ContentSkeleton, +} from './DynamicTrackingSkeleton'; diff --git a/src/views/Company/components/DynamicTracking/index.js b/src/views/Company/components/DynamicTracking/index.js index 71b14540..3110220a 100644 --- a/src/views/Company/components/DynamicTracking/index.js +++ b/src/views/Company/components/DynamicTracking/index.js @@ -1,37 +1,73 @@ // src/views/Company/components/DynamicTracking/index.js // 动态跟踪 - 独立一级 Tab 组件(包含新闻动态等二级 Tab) +// 优化:子组件懒加载,骨架屏即时反馈 -import React, { useState, useEffect, useMemo } from 'react'; +import React, { useState, useEffect, useMemo, useCallback, memo, lazy } from 'react'; import { Box } from '@chakra-ui/react'; import { FaNewspaper, FaBullhorn, FaCalendarAlt, FaChartBar } from 'react-icons/fa'; import SubTabContainer from '@components/SubTabContainer'; -import AnnouncementsPanel from '../CompanyOverview/BasicInfoTab/components/AnnouncementsPanel'; -import DisclosureSchedulePanel from '../CompanyOverview/BasicInfoTab/components/DisclosureSchedulePanel'; -import { NewsPanel, ForecastPanel } from './components'; +import { + NewsPanelSkeleton, + AnnouncementsSkeleton, + DisclosureScheduleSkeleton, + ForecastPanelSkeleton, +} from './components/DynamicTrackingSkeleton'; -// 二级 Tab 配置 +// 懒加载子组件 +const NewsPanel = lazy(() => import('./components/NewsPanel')); +const ForecastPanel = lazy(() => import('./components/ForecastPanel')); +const AnnouncementsPanel = lazy(() => + import('../CompanyOverview/BasicInfoTab/components/AnnouncementsPanel') +); +const DisclosureSchedulePanel = lazy(() => + import('../CompanyOverview/BasicInfoTab/components/DisclosureSchedulePanel') +); + +// 二级 Tab 配置(带骨架屏 fallback) const TRACKING_TABS = [ - { key: 'news', name: '新闻动态', icon: FaNewspaper, component: NewsPanel }, - { key: 'announcements', name: '公司公告', icon: FaBullhorn, component: AnnouncementsPanel }, - { key: 'disclosure', name: '财报披露日程', icon: FaCalendarAlt, component: DisclosureSchedulePanel }, - { key: 'forecast', name: '业绩预告', icon: FaChartBar, component: ForecastPanel }, + { + key: 'news', + name: '新闻动态', + icon: FaNewspaper, + component: NewsPanel, + fallback: , + }, + { + key: 'announcements', + name: '公司公告', + icon: FaBullhorn, + component: AnnouncementsPanel, + fallback: , + }, + { + key: 'disclosure', + name: '财报披露日程', + icon: FaCalendarAlt, + component: DisclosureSchedulePanel, + fallback: , + }, + { + key: 'forecast', + name: '业绩预告', + icon: FaChartBar, + component: ForecastPanel, + fallback: , + }, ]; /** * 动态跟踪组件 * * 功能: - * - 使用 SubTabContainer 实现二级导航 - * - Tab1: 新闻动态 - * - Tab2: 公司公告 - * - Tab3: 财报披露日程 - * - Tab4: 业绩预告 + * - 使用 SubTabContainer 实现二级导航(同步渲染,无 loading) + * - 子组件懒加载,减少初始包体积 + * - 每个 Tab 有专属骨架屏,提供即时视觉反馈 * * @param {Object} props * @param {string} props.stockCode - 股票代码 */ -const DynamicTracking = ({ stockCode: propStockCode }) => { +const DynamicTracking = memo(({ stockCode: propStockCode }) => { const [stockCode, setStockCode] = useState(propStockCode || '000001'); const [activeTab, setActiveTab] = useState(0); @@ -50,6 +86,11 @@ const DynamicTracking = ({ stockCode: propStockCode }) => { [stockCode] ); + // Tab 切换回调 + const handleTabChange = useCallback((index) => { + setActiveTab(index); + }, []); + return ( { componentProps={componentProps} themePreset="blackGold" index={activeTab} - onTabChange={(index) => setActiveTab(index)} + onTabChange={handleTabChange} isLazy size="sm" /> ); -}; +}); + +DynamicTracking.displayName = 'DynamicTracking'; export default DynamicTracking;