Skip to content

Commit 4d7bd9b

Browse files
ximingclaude
andcommitted
feat(web): 首页每日推荐和历史今天自动定时刷新
添加 30 分钟定时轮询、跨天检测刷新和标签页可见性刷新机制, 确保用户长时间停留在首页时数据保持更新。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent b1adf1c commit 4d7bd9b

2 files changed

Lines changed: 65 additions & 3 deletions

File tree

apps/web/src/pages/home/components/daily-recommendations.tsx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@ export function DailyRecommendations() {
2727
return `${month}${day}${weekday}`;
2828
}, []);
2929

30-
// Fetch recommendations on mount
30+
// Fetch recommendations on mount, with auto-refresh
3131
useEffect(() => {
3232
let isMounted = true;
33+
let refreshTimer: ReturnType<typeof setInterval> | null = null;
34+
let currentDay = new Date().getDate();
3335

3436
async function fetchRecommendations() {
3537
try {
@@ -59,8 +61,33 @@ export function DailyRecommendations() {
5961

6062
fetchRecommendations();
6163

64+
// Auto-refresh every 30 minutes
65+
refreshTimer = setInterval(() => {
66+
const now = new Date();
67+
// Refresh if day changed or on regular interval
68+
if (now.getDate() !== currentDay) {
69+
currentDay = now.getDate();
70+
}
71+
fetchRecommendations();
72+
}, 30 * 60 * 1000);
73+
74+
// Refresh when tab becomes visible again
75+
const handleVisibilityChange = () => {
76+
if (document.visibilityState === 'visible') {
77+
const now = new Date();
78+
if (now.getDate() !== currentDay) {
79+
currentDay = now.getDate();
80+
fetchRecommendations();
81+
}
82+
}
83+
};
84+
85+
document.addEventListener('visibilitychange', handleVisibilityChange);
86+
6287
return () => {
6388
isMounted = false;
89+
if (refreshTimer) clearInterval(refreshTimer);
90+
document.removeEventListener('visibilitychange', handleVisibilityChange);
6491
};
6592
}, []);
6693

apps/web/src/pages/home/components/on-this-day-banner.tsx

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,57 @@ export const OnThisDayBanner = view(() => {
2929
const scrollContainerRef = useRef<HTMLDivElement>(null);
3030

3131
useEffect(() => {
32+
let isMounted = true;
33+
let refreshTimer: ReturnType<typeof setInterval> | null = null;
34+
let currentDay = new Date().getDate();
35+
3236
const fetchOnThisDayMemos = async () => {
3337
setIsLoading(true);
3438
try {
3539
const response = await memoApi.getOnThisDayMemos();
40+
if (!isMounted) return;
3641
if (response.code === 0 && response.data) {
37-
// Take at most 5 memos for the banner
3842
setMemos(response.data.items.slice(0, 5));
3943
}
4044
} catch (error) {
45+
if (!isMounted) return;
4146
console.error('Failed to fetch on this day memos:', error);
4247
} finally {
43-
setIsLoading(false);
48+
if (isMounted) {
49+
setIsLoading(false);
50+
}
4451
}
4552
};
4653

4754
fetchOnThisDayMemos();
55+
56+
// Auto-refresh every 30 minutes
57+
refreshTimer = setInterval(() => {
58+
const now = new Date();
59+
if (now.getDate() !== currentDay) {
60+
currentDay = now.getDate();
61+
}
62+
fetchOnThisDayMemos();
63+
}, 30 * 60 * 1000);
64+
65+
// Refresh when tab becomes visible again and day has changed
66+
const handleVisibilityChange = () => {
67+
if (document.visibilityState === 'visible') {
68+
const now = new Date();
69+
if (now.getDate() !== currentDay) {
70+
currentDay = now.getDate();
71+
fetchOnThisDayMemos();
72+
}
73+
}
74+
};
75+
76+
document.addEventListener('visibilitychange', handleVisibilityChange);
77+
78+
return () => {
79+
isMounted = false;
80+
if (refreshTimer) clearInterval(refreshTimer);
81+
document.removeEventListener('visibilitychange', handleVisibilityChange);
82+
};
4883
}, []);
4984

5085
// Handle horizontal scroll with mouse wheel

0 commit comments

Comments
 (0)