Вопрос или проблема
В настоящее время я пытаюсь реализовать шапку, которая появляется при прокрутке вверх и исчезает при прокрутке вниз, но когда я помещаю мой элемент шапки внутрь StickyHeaderComponent
, логика внутри onViewableItemsChanged
(проверяет, прокрутил ли пользователь близко к низу, смотря на индекс поста, который в настоящее время просматривается, и если это так, следующая партия постов запрашивается) перестала выполняться (при прокрутке он ведет себя так, как будто текущие просматриваемые элементы не изменились), и из-за этого я не могу вызвать свой API для получения дополнительных элементов.
Это FlatList
с его viewabilityConfig
:
const viewabilityConfig = useRef({
viewAreaCoveragePercentThreshold: 20,
waitForInteraction: false,
}).current
<Animated.FlatList
className="w-full"
style={{
zIndex: 1
}}
data={data?.pages.flat()}
keyExtractor={item => {
return item._id
}}
showsVerticalScrollIndicator={false}
onScroll={Animated.event(
[
{
nativeEvent: {
contentOffset: { y: scrollY }
}
}
],
{
useNativeDriver: true
}
)}
onViewableItemsChanged={({ viewableItems }) => {
const lastVisibleItem = viewableItems[viewableItems.length - 1];
if (lastVisibleItem) {
const { index } = lastVisibleItem;
//Проверяет, если последний просмотренный элемент был близко к низу, и если это так, следующая партия постов запрашивается
if (index >= data.pages.flat().length - 3) {
fetchNextPage();
}
}
}}
viewabilityConfig={viewabilityConfig}
StickyHeaderComponent={() => (
<Animated.View
style={{
zIndex: 10,
position: "absolute",
height: HEADER_HEIGHT,
transform: [{
translateY: Animated.add(scrollY, diffClampScrollY.interpolate({
inputRange: [0, HEADER_HEIGHT],
outputRange: [0, -HEADER_HEIGHT],
extrapolate: "clamp"
}))
}]
}}
className="w-full bg-[#0F0F0F]"
>
</Animated.View>
)}
stickyHeaderIndices={[0]}
renderItem={(item) => {
return (
<PostItem>
</PostItem>
)
}}
/>
Ответ или решение
При использовании компонента FlatList
с заголовком, который "липнет" (sticky header), часто возникают проблемы с событием onViewableItemsChanged
, особенно если вы пытаетесь реализовать функциональность загрузки дополнительных данных при прокрутке. Ваша проблема может быть связана с тем, как определяется область видимости элементов в списке, когда вы используете StickyHeaderComponent
.
Вот полный план решения вашей проблемы:
-
Проверьте индексы видимых элементов: Убедитесь, что ваш
StickyHeaderComponent
не мешает вычислениям индексов видимых элементов. Как правило,onViewableItemsChanged
не запускается, если заголовок скрывает видимые элементы. Проверьте, правильно ли вы используетеstickyHeaderIndices
. -
Измените
viewabilityConfig
: Попробуйте изменить ваши значения вviewabilityConfig
, чтобы убедиться, что они соответствуют нужным параметрам. Например:const viewabilityConfig = useRef({ itemVisiblePercentThreshold: 50, // Элемент должен быть виден на 50% для регистрации }).current;
-
Обработка событий прокрутки: Если
onViewableItemsChanged
не работает корректно, вы можете использоватьonScroll
, чтобы вручную отслеживать положение прокрутки, и затем вычислить последний видимый элемент. Например:let lastScrollY = 0; const handleScroll = Animated.event( [{ nativeEvent: { contentOffset: { y: scrollY } } }], { listener: (event) => { const currentScrollY = event.nativeEvent.contentOffset.y; if (currentScrollY - lastScrollY > 200) { // Событие прокрутки вниз } else if (lastScrollY - currentScrollY > 200) { // Событие прокрутки вверх } lastScrollY = currentScrollY; }, useNativeDriver: false, // Измените на true, если требуется } );
-
Добавьте обработку
onViewableItemsChanged
: Убедитесь, что вы обращаетесь к правильным индексам элементов при реализации логики вonViewableItemsChanged
. Вот пример, как это можно сделать:const onViewableItemsChanged = useCallback(({ viewableItems }) => { if (viewableItems.length > 0) { const lastVisibleItem = viewableItems[viewableItems.length - 1]; const { index } = lastVisibleItem; if (index >= data.pages.flat().length - 3) { fetchNextPage(); } } }, [data, fetchNextPage]);
-
Обновление состояния: Убедитесь, что состояние компонента правильно обновляется при загрузке новых данных, чтобы избежать проблем с повторными запросами.
Ниже представлен полный пример вашего импортируемого компонента FlatList
с учётом изменений:
<Animated.FlatList
className="w-full"
data={data?.pages.flat()}
keyExtractor={(item) => item._id}
showsVerticalScrollIndicator={false}
onScroll={handleScroll}
onViewableItemsChanged={onViewableItemsChanged}
viewabilityConfig={viewabilityConfig}
StickyHeaderComponent={() => (
<Animated.View
style={{
zIndex: 10,
position: "absolute",
height: HEADER_HEIGHT,
transform: [{
translateY: Animated.add(scrollY, diffClampScrollY.interpolate({
inputRange: [0, HEADER_HEIGHT],
outputRange: [0, -HEADER_HEIGHT],
extrapolate: "clamp"
}))
}]
}}
className="w-full bg-[#0F0F0F]"
>
</Animated.View>
)}
stickyHeaderIndices={[0]}
renderItem={({ item }) => (
<PostItem item={item} />
)}
/>
Следуя этим рекомендациям, вы сможете устранить проблему с причиной блокировки onViewableItemsChanged
и обеспечить правильную загрузку данных при прокрутке.