From 35626f7fbec775794e3d6233a4ec9cb6464f2b7c Mon Sep 17 00:00:00 2001 From: yandadaFreedom Date: Thu, 18 Jun 2026 12:08:13 +0800 Subject: [PATCH] fix(webpack-plugin): avoid duplicate change in RN label controls --- .../runtime/components/react/getInnerListeners.ts | 14 ++++++++++++++ .../lib/runtime/components/react/mpx-checkbox.tsx | 3 ++- .../lib/runtime/components/react/mpx-label.tsx | 6 ++++-- .../lib/runtime/components/react/mpx-radio.tsx | 3 ++- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/packages/webpack-plugin/lib/runtime/components/react/getInnerListeners.ts b/packages/webpack-plugin/lib/runtime/components/react/getInnerListeners.ts index 894b6290ca..1e520ee766 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/getInnerListeners.ts +++ b/packages/webpack-plugin/lib/runtime/components/react/getInnerListeners.ts @@ -19,6 +19,20 @@ const globalEventState: GlobalEventState = { identifier: null } +const labelControlHandledEvents = new WeakSet() + +export const markLabelControlHandled = (evt: any) => { + const { nativeEvent } = evt + if (nativeEvent && typeof nativeEvent === 'object') { + labelControlHandledEvents.add(nativeEvent) + } +} + +export const isLabelControlHandled = (evt: any) => { + const { nativeEvent } = evt + return !!(nativeEvent && typeof nativeEvent === 'object' && labelControlHandledEvents.has(nativeEvent)) +} + const getTouchEvent = ( type: string, event: ExtendedNativeTouchEvent, diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-checkbox.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-checkbox.tsx index 3a9c646202..b375a408e8 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-checkbox.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-checkbox.tsx @@ -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, useTextPassThroughValue } from './utils' @@ -125,6 +125,7 @@ const Checkbox = forwardRef, CheckboxProps>( const onTap = (evt: NativeSyntheticEvent) => { bindtap && bindtap(getCustomEvent('tap', evt, { layoutRef }, props)) + markLabelControlHandled(evt) onChange(evt) } diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-label.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-label.tsx index 0633dbf26e..ed457a9b12 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-label.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-label.tsx @@ -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, useTextPassThroughValue } from './utils' import { LabelContext, LabelContextValue } from './context' @@ -74,7 +74,9 @@ const Label = forwardRef, LabelProps>( const onTap = useCallback((evt: NativeSyntheticEvent) => { 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( diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-radio.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-radio.tsx index 8928325270..c089d34cab 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-radio.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-radio.tsx @@ -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, useTextPassThroughValue } from './utils' import Icon from './mpx-icon' @@ -114,6 +114,7 @@ const Radio = forwardRef, RadioProps>( const onTap = (evt: NativeSyntheticEvent) => { bindtap && bindtap(getCustomEvent('tap', evt, { layoutRef }, props)) + markLabelControlHandled(evt) onChange(evt) }