DOM 操作优化与缓存管理

性能优化 - React.memo、API并行化、useReducer重构
This commit is contained in:
zdl
2026-01-15 17:50:05 +08:00
parent 6cf9dca324
commit afdc94049c
4 changed files with 74 additions and 38 deletions

View File

@@ -1,5 +1,5 @@
// HeroPanel - 综合日历组件
import React, { useState, useEffect, useCallback, Suspense, lazy, memo } from "react";
import React, { useState, useEffect, useCallback, Suspense, lazy, memo, useRef } from "react";
import {
Box,
HStack,
@@ -43,12 +43,23 @@ const CombinedCalendar = memo(({ DetailModal }) => {
const [detailLoading, setDetailLoading] = useState(false);
const [modalOpen, setModalOpen] = useState(false);
// 加载日历综合数据(一次 API 调用获取所有数据
// 月份数据缓存(避免切换月份后再切回时重复请求
const monthCacheRef = useRef({});
// 加载日历综合数据(带缓存)
useEffect(() => {
const loadCalendarCombinedData = async () => {
const year = currentMonth.getFullYear();
const month = currentMonth.getMonth() + 1;
const cacheKey = `${year}-${month}`;
// 检查缓存
if (monthCacheRef.current[cacheKey]) {
setCalendarData(monthCacheRef.current[cacheKey]);
return;
}
try {
const year = currentMonth.getFullYear();
const month = currentMonth.getMonth() + 1;
const response = await fetch(
`${getApiBase()}/api/v1/calendar/combined-data?year=${year}&month=${month}`
);
@@ -63,10 +74,8 @@ const CombinedCalendar = memo(({ DetailModal }) => {
eventCount: item.event_count || 0,
indexChange: item.index_change,
}));
console.log(
"[HeroPanel] 加载日历综合数据成功,数据条数:",
formattedData.length
);
// 存入缓存
monthCacheRef.current[cacheKey] = formattedData;
setCalendarData(formattedData);
}
}

View File

@@ -268,14 +268,23 @@ const DetailModal = ({
[dispatch, isStockInWatchlist]
);
// 加载股票行情(并行加载优化
// 加载股票行情(并行加载 + 缓存去重
const loadStockQuotes = useCallback(
async (stocks) => {
if (!stocks || stocks.length === 0) return;
// 过滤已缓存的股票,只请求未缓存的
const uncachedStocks = stocks.filter(
(stock) => !stockQuotes[stock.code]
);
// 如果全部已缓存,无需请求
if (uncachedStocks.length === 0) return;
setStockQuotesLoading(true);
// 并行发起所有请求
const promises = stocks.map(async (stock) => {
// 并行发起未缓存股票的请求
const promises = uncachedStocks.map(async (stock) => {
const code = getSixDigitCode(stock.code);
try {
const response = await fetch(
@@ -304,18 +313,18 @@ const DetailModal = ({
// 等待所有请求完成
const results = await Promise.all(promises);
// 构建 quotes 对象
const quotes = {};
// 合并新数据到现有缓存
const newQuotes = { ...stockQuotes };
results.forEach((result) => {
if (result) {
quotes[result.stockCode] = result.quote;
newQuotes[result.stockCode] = result.quote;
}
});
setStockQuotes(quotes);
setStockQuotes(newQuotes);
setStockQuotesLoading(false);
},
[setStockQuotes, setStockQuotesLoading]
[stockQuotes, setStockQuotes, setStockQuotesLoading]
);
// 显示相关股票

View File

@@ -4,7 +4,7 @@
* Y轴板块热度涨停家数
* 支持时间滑动条查看历史数据
*/
import React, { useState, useEffect, useMemo, useCallback } from "react";
import React, { useState, useEffect, useMemo, useCallback, useRef } from "react";
import {
Box,
Text,
@@ -38,6 +38,9 @@ import {
/**
* ThemeCometChart 主组件
*/
// 缓存有效期5 分钟)
const CACHE_DURATION = 5 * 60 * 1000;
const ThemeCometChart = ({ onThemeSelect }) => {
const [loading, setLoading] = useState(true);
const [allDatesData, setAllDatesData] = useState({});
@@ -48,8 +51,24 @@ const ThemeCometChart = ({ onThemeSelect }) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const toast = useToast();
// 加载所有日期的数据
// 数据缓存(避免 tab 切换时重复请求)
const dataCacheRef = useRef({ data: null, dates: null, timestamp: null });
// 加载所有日期的数据(带缓存)
const loadAllData = useCallback(async () => {
// 检查缓存是否有效5分钟内
const now = Date.now();
if (
dataCacheRef.current.timestamp &&
now - dataCacheRef.current.timestamp < CACHE_DURATION &&
dataCacheRef.current.data
) {
setAllDatesData(dataCacheRef.current.data);
setAvailableDates(dataCacheRef.current.dates);
setLoading(false);
return;
}
setLoading(true);
try {
const apiBase = getApiBase();
@@ -109,6 +128,12 @@ const ThemeCometChart = ({ onThemeSelect }) => {
}
});
// 存入缓存
dataCacheRef.current = {
data: dataCache,
dates: dates,
timestamp: Date.now(),
};
setAllDatesData(dataCache);
setSliderIndex(0);
} else {