ข้ามไปยังเนื้อหาหลัก

การปัดรายการบน Mobile

เอกสารนี้สรุปเคสที่เจอบ่อยใน React Native list: ปัดรายการแล้วเห็นปุ่ม action แต่กดปุ่มแล้วไม่มีอะไรเกิดขึ้น

อาการ

  • ปัด row แล้วเห็นปุ่ม action
  • log ใน renderLeftActions หรือ renderRightActions ออก
  • log ใน onPress ของปุ่ม action ไม่ออก
  • อาการดูเหมือน permission หรือ business rule ผิด แต่จริง ๆ press event ไปไม่ถึงปุ่ม

สาเหตุ

SwipeableFlashList วางปุ่ม action ไว้ด้านหลัง card แล้วขยับ card ด้วย translateX

ถ้า layer ของ card ยังสูงกว่า action area อยู่ จะเกิดเคสที่เห็นปุ่มแล้ว แต่พื้นที่ tap ยังถูก card layer กินอยู่ ใน repo นี้ itemContent มี zIndex: 1 อยู่แล้ว ดังนั้น action layer ต้องถูกยกขึ้นให้สูงกว่า card

วิธีแก้

ใน apps/mobile/src/components/SwipeableFlashList/index.tsx:

  • ใส่ pointerEvents="box-none" ที่ wrapper ของ action และ inner action content
  • ให้ action wrapper เป็น pointerEvents="none" จนกว่า row จะถูกเปิดจาก swipe จริง ไม่อย่างนั้นปุ่มที่ยังมองไม่เห็นอาจกดได้ก่อน swipe
  • ใส่ zIndex และ elevation ให้ leftActions และ rightActions สูงกว่า itemContent
  • ถ้าต้อง debug disabled state ให้ Pressable ยังรับ tap ได้ แล้วค่อยเรียก config.onPress?.() แบบมีเงื่อนไข

โครง action layer ที่ควรใช้:

<Animated.View
pointerEvents={actionsTouchable ? 'box-none' : 'none'}
style={[styles.leftActions, leftActionStyle]}
>
<View pointerEvents="box-none" style={styles.actionContent}>
{leftActions}
</View>
</Animated.View>

ตั้ง actionsTouchable เป็น true เฉพาะตอน pan gesture ตัดสินใจเปิด row แล้ว และตั้งกลับเป็น false เมื่อ close/reset วิธีนี้กันไม่ให้ปุ่ม action ที่ยังมองไม่เห็นถูกกดได้ แต่ยังให้ปุ่มที่เปิดจาก swipe แล้วกดได้ปกติ

style ที่ควรมี:

leftActions: {
...StyleSheet.absoluteFill,
zIndex: 2,
elevation: 2,
},
rightActions: {
...StyleSheet.absoluteFill,
zIndex: 2,
elevation: 2,
},
itemContent: {
width: '100%',
zIndex: 1,
},

Checklist เวลาดีบัก

  1. ใส่ log ใน renderLeftActions และ renderRightActions
  2. ใส่ log ใน onPress ของ Pressable
  3. ถ้า render log ออก แต่ press log ไม่ออก ให้ตรวจ layer ของ swipe action ก่อนตรวจ permission
  4. เช็ค direction ของ swipe:
    • leftActions เปิดเมื่อ “ลาก row ไปทางขวา”
    • rightActions เปิดเมื่อ “ลาก row ไปทางซ้าย”
  5. ถ้า action เป็น disabled-looking state แต่ต้องการ debug ให้คง Pressable ไว้ แล้วเรียก config.onPress?.() เฉพาะตอนมี action จริง

ตัวอย่างจาก Invoice

invoiceListScreen ใช้ pattern นี้กับปุ่มยกเลิกใบแจ้งหนี้ log ที่ควรเห็นคือ:

  • [InvoiceListScreen] cancel swipe render
  • [InvoiceListScreen] swipe action press
  • [InvoiceListScreen] cancel swipe press

เวลาเช็คเจ้าของเอกสารให้ log ทั้ง:

  • loginUserCode
  • invoiceUserCode
  • rawInvoiceUserCode

ก่อนเทียบ owner ต้อง normalize user code เพราะ API อาจส่งเลขที่ไม่มี 0 นำหน้า เช่น 12265 แต่ user login เป็น 012265 ซึ่งต้องถือว่าเป็น user เดียวกัน