fix: implement fetch generation counter to handle concurrent refreshes in ScrollingList
Some checks failed
Chore App Build, Test, and Push Docker Images / build-and-push (push) Has been cancelled
Some checks failed
Chore App Build, Test, and Push Docker Images / build-and-push (push) Has been cancelled
- Added a fetch generation counter to the fetchItems method to discard stale results from concurrent fetches. - Updated the loading state management to ensure it only updates if the fetch is the latest. - Enhanced the refresh method to prevent stale data from being rendered when multiple refreshes occur. - Added a test case to verify that stale fetches are discarded correctly when concurrent refreshes happen. - Fixed CSS for mobile banners to prevent overflow and adjusted font sizes for better visibility. - Resolved issues with task icons disappearing when extending time on overdue chores by ensuring only one fetch is active at a time.
This commit is contained in:
@@ -39,14 +39,19 @@ const scrollWrapper = ref<HTMLDivElement | null>(null)
|
||||
const itemRefs = ref<Record<string, HTMLElement | Element | null>>({})
|
||||
const lastCenteredItemId = ref<string | null>(null)
|
||||
|
||||
let fetchGeneration = 0
|
||||
|
||||
const fetchItems = async () => {
|
||||
const thisGeneration = ++fetchGeneration
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const resp = await fetch(fetchUrl.value)
|
||||
if (thisGeneration !== fetchGeneration) return
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
||||
const data = await resp.json()
|
||||
if (thisGeneration !== fetchGeneration) return
|
||||
// Try to use 'tasks', 'reward_status', or 'items' as fallback
|
||||
let itemList = data[props.itemKey || 'items'] || []
|
||||
if (props.filterFn) itemList = itemList.filter(props.filterFn)
|
||||
@@ -75,18 +80,23 @@ const fetchItems = async () => {
|
||||
}
|
||||
}),
|
||||
)
|
||||
if (thisGeneration !== fetchGeneration) return
|
||||
// Re-assign to trigger Vue reactivity for image URLs set on raw objects
|
||||
items.value = [...itemList]
|
||||
} catch (err) {
|
||||
if (thisGeneration !== fetchGeneration) return
|
||||
error.value = err instanceof Error ? err.message : 'Failed to fetch items'
|
||||
items.value = []
|
||||
console.error('Error fetching items:', err)
|
||||
} finally {
|
||||
loading.value = false
|
||||
if (thisGeneration === fetchGeneration) {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
await fetchItems()
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const scrollToItem = async (itemId: string) => {
|
||||
|
||||
Reference in New Issue
Block a user