Flatlist onViewableItemsChanged блокируется при использовании залипающего заголовка

Вопрос или проблема

В настоящее время я пытаюсь реализовать шапку, которая появляется при прокрутке вверх и исчезает при прокрутке вниз, но когда я помещаю мой элемент шапки внутрь 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.

Вот полный план решения вашей проблемы:

  1. Проверьте индексы видимых элементов: Убедитесь, что ваш StickyHeaderComponent не мешает вычислениям индексов видимых элементов. Как правило, onViewableItemsChanged не запускается, если заголовок скрывает видимые элементы. Проверьте, правильно ли вы используете stickyHeaderIndices.

  2. Измените viewabilityConfig: Попробуйте изменить ваши значения в viewabilityConfig, чтобы убедиться, что они соответствуют нужным параметрам. Например:

    const viewabilityConfig = useRef({
     itemVisiblePercentThreshold: 50, // Элемент должен быть виден на 50% для регистрации
    }).current;
  3. Обработка событий прокрутки: Если 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, если требуется
     }
    );
  4. Добавьте обработку 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]);
  5. Обновление состояния: Убедитесь, что состояние компонента правильно обновляется при загрузке новых данных, чтобы избежать проблем с повторными запросами.

Ниже представлен полный пример вашего импортируемого компонента 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 и обеспечить правильную загрузку данных при прокрутке.

Оцените материал
Добавить комментарий

Капча загружается...