-
Notifications
You must be signed in to change notification settings - Fork 294
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
onViewableItemsChanged not firing if items change without scroll 😔 #614
Comments
This is the only FlashList issue that I haven't found a good solution to. If the FlashList data changes, then This issue means that we can't do anything in response to new data without either throwing away some efficient algorithms or doing some really crazy tracking of offsets. For example, I have a list of
For now, I'll probably do 1. and create a debounced batch queue so it can collect what I need after items have been rendered for a small delay (and to avoid rendering stuff that's just scrolling by). Still, it seems like this should be fix, because the workarounds are a real PITA. Edit: I implemented solution 1, which works, but not ideally, since FlashList renders a bunch of non-viewable items as well. Back to the drawing board. |
@mfbx9da4 have you tried to add a keyExtractor to it? We had similar issues and using a keyExtractor only with index was enough for our use case to fix this issue. |
@hirbod Not OP, but my setup implements:
Anyways, looking at the underlying code, it's relatively clear that the issue for me is the fact that FlashList sort of conflates "visible indices" with "visible items". Frequently, new items can be added, without the visible indices changing at all. It's very likely, therefore, that the reason I would occasionally see this fire, is because adding a new item would change the layout in such a way that visible indices changes (probably because I'm using Note that I have not verified this. I just looked at the code and the fact that FlashList relies on the underlying On my end, I already found a workaround, and that is keeping a reference to the visible indices. If something new comes in and it's within the visible range, I make sure the extra data is loaded. Looks something like: type ViewRange = [startIdx: number, endIdx: number]
const DEFAULT_VIEW_RANGE: ViewRange = [0, 1]
// List
const viewRangeRef = useRef(DEFAULT_VIEW_RANGE)
const handleViewableItemsChanged = ({ viewableItems }: FooViewabilityInfo) => {
viewRangeRef.current[0] = viewableItems[0]?.index || 0
viewRangeRef.current[1] = viewableItems[viewableItems.length - 1]?.index || 1
} Not ideal, but it'll work until this is fixed. |
Same problem here, but it appears to be happening only on android. onviewableItemsChanged does fire as expected. However, I have tried using the json data id and the index as the keyextractor prop. Both result in the same issue. This pretty much makes it impossible to use flashlist where we need to keep track of which items are inside the viewport. Edit: Setting itemVisiblePercentThreshold to 50 instead of 100 fixed my problem! |
How do you get notified if the new item is being rendered though? What is |
@hirbod I tried adding a key extractor didn't help. Have you tried the example? @eeshankeni I tried playing with |
From a brief read of the code it looks like the ViewabilityManger is only tracking indices so fundamentally it will not work as expected
I wonder if this comes down to the fact that recycler list view does not support |
For my particular use case all I care about is if the first visible item changed I built a hook for this inspired from @bfricka's comment. A similar strategy could be used to fully fix FlashList import { FlashList, ViewToken } from '@shopify/flash-list'
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'
import { Button, Text, ViewabilityConfig } from 'react-native'
function isTruthy<T>(x: T): x is Exclude<T, Falsy> {
return x !== null && x !== undefined && (x as any) !== false
}
const viewabilityConfig: ViewabilityConfig = {
itemVisiblePercentThreshold: 50,
}
export function ExampleFlashList() {
const [data, setData] = useState(() => Array.from({ length: 100 }, (_, i) => i))
console.log('=================')
const ref = useRef<FlashList<any>>(null)
const notifyVisibleItemsChanged = useFirstVisibleItemChanged(data, item => {
console.log('newly visible first item', item)
})
const handleViewableItemsChanged = useCallback(
(info: { viewableItems: ViewToken[]; changed: ViewToken[] }) => {
notifyVisibleItemsChanged(info)
console.log('handleViewableItemsChanged')
},
[notifyVisibleItemsChanged]
)
return (
<FlashList
ref={ref}
data={data}
inverted
ListHeaderComponent={
<Button
title="Add more items"
onPress={() => {
setData(x => [...Array.from({ length: 10 }, (_, i) => x[0] - (10 - i)), ...x])
}}
/>
}
onViewableItemsChanged={handleViewableItemsChanged}
renderItem={renderItem}
estimatedItemSize={40}
viewabilityConfig={viewabilityConfig}
keyboardDismissMode="interactive"
keyboardShouldPersistTaps="handled"
onEndReachedThreshold={0.5}
/>
)
}
function useFirstVisibleItemChanged<T>(
data: T[],
onFirstVisibleItemChanged: (item: { item: T; index: number }) => void
) {
const viewableIndicesRef = useRef<number[]>([])
const callbackRef = useRef(onFirstVisibleItemChanged)
callbackRef.current = onFirstVisibleItemChanged
const firstVisibleItemRef = useRef<T | null>(null)
const firstVisibleItem = data[viewableIndicesRef.current[0]]
useLayoutEffect(() => {
if (firstVisibleItem !== firstVisibleItemRef.current) {
callbackRef.current({ item: firstVisibleItem, index: viewableIndicesRef.current[0] })
firstVisibleItemRef.current = firstVisibleItem
}
}, [firstVisibleItem])
const trackVisibleIndices = useCallback(
(info: { viewableItems: ViewToken[]; changed: ViewToken[] }) => {
viewableIndicesRef.current = info.viewableItems.map(v => v.index).filter(isTruthy)
},
[]
)
return trackVisibleIndices
}
function renderItem({ item }: { item: number }) {
return <Text>Item: {item}</Text>
} |
The problem its not if is firing or not, the problem is because the Component still static and nothing change. |
Still not fix? |
same problem |
onViewableItemsChanged not fire every time even after change in viewabilityConfig.I used Flatlist as a pager in class componant where I want the current visible item index. onViewableItemsChanged is ony fire at the last index . How coud I get the Index .. please help.. |
no fix? |
I've seen a couple of issues mentioning onViewableItemsChanged not working but thought I should open a new one because they don't provide reproducible examples and I found them a bit unclear
Current behavior
Adding new items to the FlashList does not cause the
onViewableItemsChanged
to be fired.To Reproduce
Try tapping the button once loaded, the handler does not fire.
Platform:
Android (untested)
Environment
1.2.2
The text was updated successfully, but these errors were encountered: