React Native中实现Swipeable组件单次仅展开一个项的问题求助
解决react-native-gesture-handler/Swipeable单次仅展开一个项的问题
你的核心问题在于每个Swipeable子组件的状态完全独立,当前代码里的row数组和prevOpenedRow变量会在组件每次渲染时重置,无法跨子组件实例跟踪和控制已展开的行。以下是具体修正方案:
问题代码的关键缺陷
row和prevOpenedRow是组件内的普通变量,每次Sample组件渲染都会重新初始化,无法保存跨组件的状态onSwipeableOpen={closeSwipable(index)}是直接执行函数而非传递回调,会在组件渲染时就触发,不是滑动打开时执行- 未利用全局/父组件状态统一管理所有可滑动项的展开状态
修正方案:状态提升到父组件
把所有可滑动项的ref和当前展开项的状态放到父组件中,通过props传递控制逻辑给子组件:
1. 父组件代码
import React, { useRef, useState } from 'react'; import { FlatList } from 'react-native'; import Sample from './Sample'; // 引入你的子组件 const ParentComponent = ({ dataList }) => { // 保存所有Swipeable组件的引用 const swipeRefs = useRef([]); // 记录当前展开的行索引 const [openedIndex, setOpenedIndex] = useState(null); // 关闭当前展开行之外的所有行 const closeOtherRows = (currentIndex) => { if (openedIndex !== null && openedIndex !== currentIndex) { swipeRefs.current[openedIndex]?.close(); } setOpenedIndex(currentIndex); }; // 关闭所有已展开的行 const closeAllRows = () => { if (openedIndex !== null) { swipeRefs.current[openedIndex]?.close(); setOpenedIndex(null); } }; return ( <FlatList data={dataList} renderItem={({ item, index }) => ( <Sample data={item} index={index} swipeRef={(ref) => (swipeRefs.current[index] = ref)} onSwipeOpen={() => closeOtherRows(index)} onActionPress={closeAllRows} // 传递你的业务回调 onClickAdd={() => {/* 你的添加逻辑 */}} onClickRemove={() => {/* 你的删除逻辑 */}} /> )} keyExtractor={(item) => item.TI} /> ); }; export default ParentComponent;
2. 修正后的子组件(Sample)代码
import React from 'react'; import { TouchableOpacity, View, Animated } from 'react-native'; import Swipeable from "react-native-gesture-handler/Swipeable"; const Sample = ({ data, index, swipeRef, onSwipeOpen, onActionPress, onClickAdd, onClickRemove }) => { const rightSwipeActions = (progress, dragX) => { return ( <> <TouchableOpacity onPress={() => { onClickAdd(); onActionPress(); }}> <View style={[styles.swipeButtonView, styles.swipeAddButton]}> <Animated.Text style={styles.swipeButtonText}>add</Animated.Text> </View> </TouchableOpacity> <TouchableOpacity onPress={() => { onClickRemove(); onActionPress(); }}> <View style={[styles.swipeButtonView, styles.swipeRemoveButton]}> <Animated.Text style={styles.swipeButtonText}>remove</Animated.Text> </View> </TouchableOpacity> </> ); }; return ( <Swipeable friction={2} renderRightActions={rightSwipeActions} ref={swipeRef} leftThreshold={80} rightThreshold={40} onSwipeableOpen={onSwipeOpen} key={data?.TI} > <TouchableOpacity style={{ flexDirection: "row", backgroundColor: "white", alignItems: "center", paddingVertical: 16, paddingHorizontal: 12, }} activeOpacity={1} onPress={onActionPress} // 点击行本身也关闭展开项 > {/* 这里放置你的行内容,比如展示data的具体字段 */} </TouchableOpacity> </Swipeable> ); }; // 补充你的样式定义 const styles = { swipeButtonView: { justifyContent: 'center', alignItems: 'center', width: 80, height: '100%', }, swipeAddButton: { backgroundColor: '#2ecc71', }, swipeRemoveButton: { backgroundColor: '#e74c3c', }, swipeButtonText: { color: 'white', fontWeight: '600', }, }; export default Sample;
核心逻辑说明
- 父组件通过
swipeRefs统一保存所有子组件的Swipeable引用,openedIndex记录当前展开的行索引 - 当某一行滑动打开时,触发
onSwipeOpen调用父组件的closeOtherRows,关闭之前展开的行并更新当前索引 - 点击操作按钮或行本身时,调用
closeAllRows关闭当前展开的行
内容的提问来源于stack exchange,提问作者Manish Kumar
相关产品推荐
相关产品推荐

