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

React Native中TouchableOpacity onPress多次触发导航重复跳转问题

解决快速点击导致多次导航的问题

方案1:防抖函数限制触发频率

通过防抖函数确保短时间内(默认300ms)只有第一次点击生效,后续重复点击会被忽略。

先定义防抖工具函数:

const debounce = (func, delay = 300) => {
  let timerId;
  return (...args) => {
    if (timerId) clearTimeout(timerId);
    timerId = setTimeout(() => func.apply(this, args), delay);
  };
};

在FlatList所在的父组件中,用防抖包装导航逻辑:

// 定义防抖后的导航函数
const navigateToProduct = debounce((item) => {
  navigation.push("product_details", {
    title: `${item.propertyType} ${currencyFormat(item.price)}`,
    id: item.id
  });
});

// 传递给ProductCard
<ProductCard 
  favorites={favorites} 
  onPress={() => navigateToProduct(item)} 
  index={index} 
  data={item} 
  style={[ favorites.length % 2 === 1 && index === favorites.length - 1 && {marginRight: 28} ]}
/>

方案2:状态锁阻止重复点击

在组件内维护一个状态标记是否正在处理导航,点击后立刻锁定,导航完成或超时后解锁。

父组件中处理:

import { useState } from 'react';

// 父组件内定义状态
const [isNavigating, setIsNavigating] = useState(false);

const handleNavigate = (item) => {
  if (isNavigating) return;
  setIsNavigating(true);
  navigation.push("product_details", {
    title: `${item.propertyType} ${currencyFormat(item.price)}`,
    id: item.id
  });
  // 页面跳转完成后解锁,避免导航失败后一直锁定
  const unsubscribe = navigation.addListener('focus', () => {
    setIsNavigating(false);
    unsubscribe();
  });
};

// 传递给ProductCard
<ProductCard 
  onPress={() => handleNavigate(item)}
  // 其他props...
/>

ProductCard内部处理:

import { useState } from 'react';

// ProductCard组件内
const [isClicked, setIsClicked] = useState(false);

const handlePress = () => {
  if (isClicked) return;
  setIsClicked(true);
  onPress(); // 调用传入的导航函数
  // 超时解锁,兜底处理导航失败的情况
  setTimeout(() => setIsClicked(false), 500);
};

// 修改TouchableOpacity的onPress
<TouchableOpacity onPress={handlePress} style={[styles.cardContainer, index % 2 === 0 ? { marginLeft: 15, marginRight: 8 } : { marginLeft: 8, marginRight: 15 }, style]}>
  // 组件原有内容...
</TouchableOpacity>

方案3:替换导航方法(适合无需重复页面场景)

如果业务允许,用navigation.navigate替代push——navigate会检查导航栈中是否已存在目标页面,若存在则直接跳转至该页面,不会新增重复页面:

onPress={() => navigation.navigate("product_details", {
  title: `${item.propertyType} ${currencyFormat(item.price)}`,
  id: item.id
})}

注意:此方案会改变导航行为,若业务需要允许同一商品打开多个详情页则不适用。

方案4:调整TouchableOpacity响应延迟(不推荐)

通过delayPressIn属性延迟点击事件触发,减少快速点击的可能性,但会影响用户点击体验:

<TouchableOpacity 
  onPress={onPress} 
  delayPressIn={300} // 延迟300ms触发点击
  style={[styles.cardContainer, index % 2 === 0 ? { marginLeft: 15, marginRight: 8 } : { marginLeft: 8, marginRight: 15 }, style]}
>
  // 组件原有内容...
</TouchableOpacity>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 21:27:36