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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 23:33:25