Skip to content
Open
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { NativeSyntheticEvent } from 'react-native'
import { useRef, useMemo } from 'react'
import { collectDataset } from '@mpxjs/utils'
import { extendObject, useNavigation } from './utils'
Expand All @@ -21,6 +22,18 @@ const globalEventState: GlobalEventState = {
identifier: null
}

type LabelControlEvent = NativeSyntheticEvent<TouchEvent & {
_labelControlHandled?: boolean
}>

export const markLabelControlHandled = (evt: LabelControlEvent) => {
evt.nativeEvent._labelControlHandled = true
}

export const isLabelControlHandled = (evt: LabelControlEvent) => {
return !!evt.nativeEvent._labelControlHandled
}

const baseRemovePropsMap: Record<string, boolean> = {
children: true,
'enable-background': true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
NativeSyntheticEvent
} from 'react-native'
import { warn } from '@mpxjs/utils'
import useInnerProps, { getCustomEvent } from './getInnerListeners'
import useInnerProps, { getCustomEvent, markLabelControlHandled } from './getInnerListeners'
import useNodesRef, { HandlerRef } from './useNodesRef'
import Icon from './mpx-icon'
import { splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren, extendObject, useTextPassThrough } from './utils'
Expand Down Expand Up @@ -120,6 +120,7 @@ const Checkbox = forwardRef<HandlerRef<View, CheckboxProps>, CheckboxProps>(
}

const onTap = (evt: NativeSyntheticEvent<TouchEvent>) => {
markLabelControlHandled(evt)
bindtap && bindtap(getCustomEvent('tap', evt, { layoutRef }, props))
onChange(evt)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { JSX, useRef, forwardRef, ReactNode, useCallback, createElement } from 'react'
import { View, ViewStyle, NativeSyntheticEvent } from 'react-native'
import { noop, warn } from '@mpxjs/utils'
import useInnerProps, { getCustomEvent } from './getInnerListeners'
import useInnerProps, { getCustomEvent, isLabelControlHandled } from './getInnerListeners'
import useNodesRef, { HandlerRef } from './useNodesRef'
import { splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren, extendObject, useTextPassThrough } from './utils'
import { LabelContext, LabelContextValue } from './context'
Expand Down Expand Up @@ -70,7 +70,9 @@ const Label = forwardRef<HandlerRef<View, LabelProps>, LabelProps>(
const onTap = useCallback((evt: NativeSyntheticEvent<TouchEvent>) => {
const { bindtap } = propsRef.current
bindtap && bindtap(getCustomEvent('tap', evt, { layoutRef }, { props: propsRef.current }))
contextRef.current.triggerChange(evt)
if (!isLabelControlHandled(evt)) {
contextRef.current.triggerChange(evt)
}
}, [])

const innerProps = useInnerProps(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { JSX, useRef, useState, forwardRef, useEffect, ReactNode, useContext, Di
import { View, StyleSheet, ViewStyle, NativeSyntheticEvent } from 'react-native'
import { warn } from '@mpxjs/utils'
import { LabelContext, RadioGroupContext } from './context'
import useInnerProps, { getCustomEvent } from './getInnerListeners'
import useInnerProps, { getCustomEvent, markLabelControlHandled } from './getInnerListeners'
import useNodesRef, { HandlerRef } from './useNodesRef'
import { splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren, extendObject, useTextPassThrough } from './utils'
import Icon from './mpx-icon'
Expand Down Expand Up @@ -109,6 +109,7 @@ const Radio = forwardRef<HandlerRef<View, RadioProps>, RadioProps>(
}

const onTap = (evt: NativeSyntheticEvent<TouchEvent>) => {
markLabelControlHandled(evt)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

markLabelControlHandled(evt) 建议放到业务 bindtap 之前。RN 的事件分发会用 guarded callback 隔离单个 listener 的异常;如果 bindtap 同步抛错,当前函数会在写入标记前退出,但原始事件仍可能继续冒泡到 label,导致 label 再执行 triggerChange,出现异常路径下状态仍被切换的情况。建议顺序调整为 markLabelControlHandled(evt)bindtap(...)onChange(evt)mpx-checkbox.tsx 中的同处逻辑也请同步调整。

bindtap && bindtap(getCustomEvent('tap', evt, { layoutRef }, props))
onChange(evt)
}
Expand Down
Loading