fix: frontend race condition — folder sync callback was reloading wrong folder
- When user switches folders quickly, syncFolder(A) callback fires after user already selected B - loadMails() was called with stale selectedFolderId, loading wrong mails - Add useRef to track current folder ID, only reload if still on same folder - Also fix backend: message_id dedup now only within same folder (not cross-folder)
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
* Account selection is integrated into the folder tree (left pane).
|
* Account selection is integrated into the folder tree (left pane).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useEffect, useCallback } from 'react';
|
import React, { useState, useEffect, useCallback, useRef } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { Card } from '@/components/ui/Card';
|
import { Card } from '@/components/ui/Card';
|
||||||
@@ -82,6 +82,12 @@ export function MailPage() {
|
|||||||
const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc');
|
const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc');
|
||||||
const [isSyncing, setIsSyncing] = useState(false);
|
const [isSyncing, setIsSyncing] = useState(false);
|
||||||
|
|
||||||
|
// Ref to track the current folder ID for async callbacks (prevents race conditions)
|
||||||
|
const selectedFolderIdRef = useRef<string | null>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
selectedFolderIdRef.current = selectedFolderId;
|
||||||
|
}, [selectedFolderId]);
|
||||||
|
|
||||||
// Load accounts
|
// Load accounts
|
||||||
const loadAccounts = useCallback(async () => {
|
const loadAccounts = useCallback(async () => {
|
||||||
setLoadingAccounts(true);
|
setLoadingAccounts(true);
|
||||||
@@ -183,9 +189,12 @@ export function MailPage() {
|
|||||||
setSelectedMailIds(new Set());
|
setSelectedMailIds(new Set());
|
||||||
setActiveView('list');
|
setActiveView('list');
|
||||||
// Live sync: fetch new mails from IMAP in background, reload after
|
// Live sync: fetch new mails from IMAP in background, reload after
|
||||||
|
// Only reload if the user hasn't switched to another folder in the meantime
|
||||||
syncFolder(folderId).then(() => {
|
syncFolder(folderId).then(() => {
|
||||||
|
if (selectedFolderIdRef.current === folderId) {
|
||||||
loadMails();
|
loadMails();
|
||||||
loadAllFolders();
|
loadAllFolders();
|
||||||
|
}
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
},
|
},
|
||||||
[folders, loadMails, loadAllFolders],
|
[folders, loadMails, loadAllFolders],
|
||||||
|
|||||||
Reference in New Issue
Block a user