React Native:解决子FlatList触发错误onScroll事件的问题
解决嵌套垂直FlatList的onScroll误触发问题
当嵌套垂直FlatList时,父列表的滚动会触发子列表的onScroll事件,这是因为滚动事件在原生层会冒泡传递。以下是几个可行的解决办法:
1. 通过事件目标匹配过滤无效滚动
给子FlatList添加ref,在onScroll的监听回调里判断触发事件的原生节点是否为子列表本身,仅当匹配时才执行动画逻辑:
import { useRef } from 'react'; import { FlatList, Animated } from 'react-native'; // 组件内部逻辑 const childFlatListRef = useRef(null); const scrollY = useRef(new Animated.Value(0)).current; const handleChildScroll = Animated.event( [{ nativeEvent: { contentOffset: { y: scrollY } } }], { useNativeDriver: false, listener: (event) => { // 对比事件目标与子FlatList的原生节点 const childNativeRef = childFlatListRef.current?.getNativeScrollRef(); if (childNativeRef && event.nativeEvent.target === childNativeRef) { // 这里执行你的自定义滚动动画逻辑 } } } ); // 渲染结构 <FlatList // 父FlatList data={parentData} renderItem={({ item }) => ( <FlatList // 子FlatList ref={childFlatListRef} data={item.childData} onScroll={handleChildScroll} // 子FlatList其他属性 /> )} />
原理:父列表滚动时,子列表接收到的onScroll事件的target是父列表的原生滚动节点,而getNativeScrollRef()能获取到子列表自身的原生节点,通过对比即可过滤掉冒泡过来的无效事件。
2. 通过触摸状态标记过滤
监听子FlatList的触摸事件,标记当前是否为用户主动触摸子列表,仅在触摸期间触发的onScroll才执行动画:
import { useState } from 'react'; import { FlatList, Animated } from 'react-native'; // 组件内部逻辑 const [isChildTouched, setIsChildTouched] = useState(false); const scrollY = useRef(new Animated.Value(0)).current; const handleChildScroll = Animated.event( [{ nativeEvent: { contentOffset: { y: scrollY } } }], { useNativeDriver: false, listener: (event) => { if (isChildTouched) { // 执行你的自定义滚动动画逻辑 } } } ); // 渲染结构 <FlatList // 父FlatList data={parentData} renderItem={({ item }) => ( <FlatList // 子FlatList data={item.childData} onScroll={handleChildScroll} onTouchStart={() => setIsChildTouched(true)} onTouchEnd={() => setIsChildTouched(false)} onTouchCancel={() => setIsChildTouched(false)} // 子FlatList其他属性 /> )} />
原理:父列表滚动不会触发子列表的触摸事件,因此只有用户主动触摸子列表时,isChildTouched才会为true,此时才会响应onScroll事件执行动画。
额外注意
你的代码中存在一个拼写错误:Flatlist应该改为FlatList(首字母大写,L大写),这可能导致组件无法正常渲染。
内容的提问来源于stack exchange,提问作者Zuka Gaprindashvili
相关产品推荐
相关产品推荐

