React Native项目出现Excessive number of pending callbacks错误求助
React Native 待处理回调数量过多(501)错误排查与解决
错误提示
请反馈:待处理回调数量过多:501。部分待处理回调可能因从未被Native代码调用而泄漏 请反馈:待处理回调数量过多:501。部分待处理回调可能因从未被Native代码调用而泄漏
相关代码
const SCREEN_WIDTH = Dimensions.get("window").width; const ProductView = ({ navigation }) => { //const getDiv = useSelector((state) => state.reducerDiv.divId) const [itemsData, setItemsData] = useState([]); const [currentIndex, setCurrentIndex] = useState(0); const [loading, setLoading] = useState(true); const route = useRoute(); const id = route.params?.id; const item = itemsData?.find((i) => i.id === id); useEffect(() => { getData(); }, []); const getData = async () => { try { const response = await axios.post(`url`); setItemsData(response.data.data); } catch (error) { console.warn(error); } finally { setLoading(false); } }; useEffect(() => { if (item) { setCurrentIndex(itemsData.indexOf(item)); } }, [item, id]); const handleScroll = (event) => { const contentOffset = event.nativeEvent.contentOffset.x; const index = Math.round(contentOffset / SCREEN_WIDTH); setCurrentIndex(index); }; // <-----------------------------------horizontal screen---------------------------------------------> const renderItem = ({ item }) => ( <View style={styles.body} key={item.id}> <ScrollView> <View style={styles.container}> <View style={{ width: SCREEN_WIDTH, paddingEnd: 50 }}> <Image source={{ uri: item.image ? item.image : null }} style={styles.productImg} resizeMode="contain" /> </View> <View style={{ paddingEnd: 50 }}> <View style={{ flex: 1, flexDirection: "row", marginTop: 15, justifyContent: "space-between" }}> <View style={{ flexDirection: "column" }}> <Text style={styles.textItem}>Brand name</Text> <Text style={styles.title}>{item?.title}</Text> </View> <View style={{ flex: 1, flexDirection: "row", justifyContent: "flex-end" }}> <TouchableOpacity> <Image source={require("../image/share.png")} style={styles.shareImg} /> </TouchableOpacity> <TouchableOpacity> <Image source={require("../image/screenshot.png")} style={styles.shareImg} /> </TouchableOpacity> </View> </View> </View> </View> </ScrollView> </View> ); if (loading) { return <Text>Loading...</Text>; } return ( <LinearGradient colors={["#7ABF49", "#13A15D"]} start={{ x: 0.99, y: 0 }} end={{ x: 1, y: 0 }} style={styles.linearGradient}> <HeaderItem navigation={navigation} /> <FlatList data={itemsData} horizontal={true} pagingEnabled={true} showsHorizontalScrollIndicator={false} onScroll={handleScroll} scrollEventThrottle={160} contentOffset={{ x: currentIndex * SCREEN_WIDTH, y: 0, }} keyExtractor={(item) => item.id.toString()} renderItem={renderItem} /> </LinearGradient> ); };
问题根源
该错误是因为状态更新与FlatList滚动事件形成循环触发,导致Native层回调堆积:
currentIndex变化时,FlatList通过contentOffset强制滚动,触发onScroll事件,再次调用setCurrentIndex,反复触发Native回调- 第二个
useEffect在item更新时也会设置currentIndex,进一步加剧循环
修复方案
1. 替换contentOffset为手动滚动
移除FlatList的contentOffset属性,改用scrollToIndex在currentIndex变化时手动控制滚动,避免循环触发:
const flatListRef = useRef(null); // 新增useEffect处理滚动 useEffect(() => { if (flatListRef.current && itemsData.length > 0) { flatListRef.current.scrollToIndex({ index: currentIndex, animated: false }); } }, [currentIndex, itemsData.length]); // 修改FlatList,添加ref并移除contentOffset <FlatList ref={flatListRef} data={itemsData} horizontal={true} pagingEnabled={true} showsHorizontalScrollIndicator={false} onScroll={handleScroll} scrollEventThrottle={160} keyExtractor={(item) => item.id.toString()} renderItem={renderItem} />
2. 优化handleScroll的状态更新逻辑
只有当计算出的索引与当前currentIndex不同时才更新状态,减少不必要的触发:
const handleScroll = (event) => { const contentOffset = event.nativeEvent.contentOffset.x; const index = Math.round(contentOffset / SCREEN_WIDTH); if (index !== currentIndex) { // 新增判断 setCurrentIndex(index); } };
3. 优化第二个useEffect的触发逻辑
添加索引判断,避免重复设置currentIndex,同时补充完整依赖项:
useEffect(() => { if (item) { const newIndex = itemsData.indexOf(item); if (newIndex !== currentIndex) { // 新增判断 setCurrentIndex(newIndex); } } }, [item, id, currentIndex, itemsData]); // 补充依赖项
4. 修复嵌套ScrollView的滚动冲突
给内部ScrollView添加nestedScrollEnabled属性,避免干扰FlatList的滚动事件:
<ScrollView nestedScrollEnabled={true}> // ...内部原有内容 </ScrollView>
内容的提问来源于stack exchange,提问作者Raja Kumar
相关产品推荐
相关产品推荐

