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

如何用react-native-gesture-handler实现点击/滑动其他项时收回已滑开列表项

React Native Gesture Handler 实现滑动列表项互斥关闭(仅保持一项展开)

我尝试用react-native-gesture-handler的Swipeable组件实现列表项的互斥滑动——当滑动或点击其他列表项时,自动收回已滑开的项。参考过相关示例和Issue但未成功,当前代码中prevOpenedRow始终输出undefined,无法实现预期效果。

原代码问题分析

  • 父组件中用普通变量prevOpenedRow和row存储状态,React组件重新渲染时这些变量会被重置,无法持久保存状态
  • 子组件修改prevOpenedRow只是操作自身接收的props副本,无法同步到父组件的变量,导致状态无法共享

解决方案

使用React的useRef持久保存所有列表项的Swipeable引用,用useState跟踪当前展开的项索引,通过父组件统一管理展开状态,实现互斥关闭。


修改后代码

List.js

import { useState, useRef } from 'react';
import { FlatList } from 'react-native';
import Child from './Child';

const List = () => {
  // 用useRef持久存储所有Swipeable组件的引用
  const rowRefs = useRef([]);
  // 用useState跟踪当前展开的项索引
  const [openRowIndex, setOpenRowIndex] = useState(null);

  // 处理行展开的方法:关闭之前的行,更新当前展开索引
  const handleRowOpen = (index) => {
    // 如果之前有展开的行,且不是当前行,关闭它
    if (openRowIndex !== null && openRowIndex !== index) {
      rowRefs.current[openRowIndex]?.close();
    }
    // 更新当前展开的索引(点击已展开行则收起)
    setOpenRowIndex(index === openRowIndex ? null : index);
  };

  return (
    <FlatList 
      data={dataArray}
      keyExtractor={(item) => item.id}
      renderItem={({ item, index }) => (
        <Child 
          item={item} 
          index={index} 
          onRowOpen={handleRowOpen}
          setRowRef={(ref) => (rowRefs.current[index] = ref)}
        />
      )}
    />
  );
};

export default List;

Child.js

import { View } from 'react-native';
import { Swipeable } from 'react-native-gesture-handler';

const Child = ({ item, index, onRowOpen, setRowRef }) => {
  // 自定义右侧滑动操作组件,根据需求替换
  const swipeRightComps = () => {
    return (
      <View style={{ width: 100, backgroundColor: '#ff4444', justifyContent: 'center', alignItems: 'center' }}>
        {/* 这里是你的右侧操作按钮,比如删除、编辑等 */}
      </View>
    );
  };

  return (
    <Swipeable
      renderRightActions={swipeRightComps}
      ref={(ref) => setRowRef(ref)}
      onSwipeableOpen={() => onRowOpen(index)}
      // 可选:点击行内容时也触发关闭其他行
      onPress={() => onRowOpen(index)}
    >
      {/* 列表项内容 */}
      <View style={{ padding: 16, borderBottomWidth: 1, borderBottomColor: '#eee' }}>
        {/* 显示item内容 */}
      </View>
    </Swipeable>
  );
};

export default Child;

关键说明

  • rowRefs.current存储所有Swipeable的引用,useRef确保组件重新渲染时引用不会丢失
  • openRowIndex跟踪当前展开的项索引,通过useState触发组件更新,保证状态同步
  • 父组件统一处理展开逻辑,子组件只负责调用父方法并传递自身引用,避免状态分散

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 15:42:29