You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中SectionList的RefreshControl在Android端无故闪烁问题求助

Android端SectionList的RefreshControl异常:未触发刷新却持续闪烁

我在SectionList组件中集成了RefreshControl,该组件在预构建阶段及iOS设备上运行完全正常,但在Android设备上偶尔会出现刷新图标未触发刷新操作却持续闪烁的异常情况。

相关代码如下:

import React, { useEffect, useState, useRef, useCallback, useContext } from 'react'
import { View, Text, AppState, RefreshControl, Pressable, SectionList } from 'react-native'
...

const AnimatedSectionList = Animated.createAnimatedComponent(SectionList)

export const DiscoverOffersScreen = ({ route }: Props) => {
  // Hooks
  const qc = useQueryClient()
  ...

  // States
  const [refreshing, setRefreshing] = useState(false)
  ...

  // Offer sections
  const [favoriteOffers, setFavoriteOffers] = useState<OfferCard[]>([])
  const [expiringOffers, setExpiringOffers] = useState<OfferCard[]>([])
  const [filteredOffers, setFilteredOffers] = useState<OfferCard[]>([])

  // Queries
  const { data, isLoading, refetch } = useQuery<OffersQuery>({
    queryKey: ['offers'],
    queryFn: getOfferCardsWithFavorites
  })

  // Animations & styling
  ...

  const load = async () => {
    try {
      registerForPushNotificationsAsync()
      const locations = await getAllBusinessLocations()
      setLocations(locations)
    }
    catch (error) {
      if (error instanceof EmptyAccessTokenError) {
        logOut(navigation)
      }
    }
  }

  // Refresh logic
  const onRefresh = async () => {
    console.log("refreshed")
    setRefreshing(true)
    await load()
    await refetch()
    refreshTimeout()
  }

  const refreshTimeout = useCallback(() => {
    setTimeout(() => {
      setRefreshing(false)
    }, 400)
  }, [])

  // Refresh queries when app is resumed from background
  useEffect(() => {
    load()
    const subscription = AppState.addEventListener('change', nextAppState => {
      if (
        appState.current.match(/inactive|background/) &&
        nextAppState === 'active'
      ) {
        onRefresh()
      }
      appState.current = nextAppState
    })
    return () => {
      subscription.remove()
    }
  }, [])

  // Define sections that are displayed
  const sections : Section[] = [
    {
      index: 0,
      title: 'My Favorites',
      data: favoriteOffers
    },
    {
      index: 1,
      title: 'Expiring Soon',
      data: expiringOffers
    },
    {
      index: 2,
      title: expiringOffers.length + favoriteOffers.length === 0 ? 'All Offers' : 'Other Offers',
      data: filteredOffers
    }
  ]

  return (
    <>
      // Header
      ...
        <AnimatedSectionList
          entering={SlideInLeft}
          exiting={SlideOutLeft.duration(200)}
          refreshControl={<RefreshControl tintColor={'#519478'} colors={['#519478']} refreshing={refreshing} onRefresh={onRefresh} />}
          contentContainerStyle={{ paddingHorizontal: '5%' }}
          stickySectionHeadersEnabled={false}
          sections={sections}
          showsVerticalScrollIndicator={false}
          showsHorizontalScrollIndicator={false}
          initialScrollIndex={0}
          ref={sectionListRef}
          keyExtractor={(item) => (item as OfferCard).offer_id.toString()}
          renderSectionHeader={(info) => (
            ...
          )}
          renderItem={({ item, index, section }) => {
            return <FloatingOfferCard card={item as OfferCard}/>
          }}
        />
       ...
      </View>
    </>
  )
}

项目中还使用了react-query和react-native-reanimated库。


问题分析

当前代码的几个潜在问题可能导致Android端的异常:

  1. 固定超时强制关闭刷新状态:用400ms固定超时设置refreshing=false,但load()和refetch()的实际耗时可能超过这个值,或者Android上异步操作时序差异导致状态更新不同步。
  2. 无锁的重复刷新触发:AppState切换到前台时直接调用onRefresh(),如果此时已有刷新操作在进行,会导致refreshing状态被多次修改,引发UI异常。
  3. 动画组件兼容性:AnimatedSectionList可能和原生RefreshControl在Android上存在状态同步的兼容性问题。

解决方案

  • 移除固定超时,基于异步操作完成状态更新:
    直接在onRefresh中等待所有异步操作完成后再关闭刷新状态,避免超时导致的状态不同步:

    const onRefresh = async () => {
      console.log("refreshed")
      setRefreshing(true)
      try {
        await load()
        await refetch()
      } finally {
        setRefreshing(false)
      }
    }
    

    同时删除refreshTimeout相关代码。

  • 添加刷新状态锁,防止重复触发:
    在onRefresh开头判断当前是否正在刷新,避免重复执行:

    const onRefresh = async () => {
      if (refreshing) return
      console.log("refreshed")
      setRefreshing(true)
      try {
        await load()
        await refetch()
      } finally {
        setRefreshing(false)
      }
    }
    
  • 测试原生SectionList排除动画组件影响:
    暂时替换AnimatedSectionList为原生SectionList,如果问题消失,可尝试升级react-native-reanimated到最新版本,或者给RefreshControl添加状态监听强制同步。

  • 优化AppState监听逻辑:
    确保AppState切换时的刷新不会和手动刷新冲突,添加状态判断并更新依赖数组:

    useEffect(() => {
      load()
      const subscription = AppState.addEventListener('change', nextAppState => {
        if (
          appState.current.match(/inactive|background/) &&
          nextAppState === 'active' &&
          !refreshing
        ) {
          onRefresh()
        }
        appState.current = nextAppState
      })
      return () => {
        subscription.remove()
      }
    }, [refreshing])
    

内容的提问来源于stack exchange,提问作者AidasV

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 22:24:55