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

React Native新架构下Fabric组件Android/iOS事件处理实现方法

React Native Fabric 组件点击事件无法透传至JS侧修复方案

Android 端问题修复

核心问题共3处:spec文件类型导入错误、receiveEvent参数传值顺序错误、事件字段与spec定义不匹配,且Fabric架构下无需手动注册事件。

1. 修正spec类型定义

原代码中声明使用BubblingEventHandler但仅导入了DirectEventHandler,类型不匹配会导致codegen生成的事件绑定逻辑失效。点击事件如果不需要向父视图冒泡,直接使用DirectEventHandler即可,修正后代码:

import type {HostComponent, ViewProps} from 'react-native';
import type {DirectEventHandler} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';

type ClickEvent = Readonly<{
  value: string;
}>;

interface NativeProps extends ViewProps {
  text: string;
  onClickHandler?: DirectEventHandler<ClickEvent>;
}

export default codegenNativeComponent<NativeProps>(
  'MyButtonView',
) as HostComponent<NativeProps>;

Fabric架构下codegen会自动完成事件注册逻辑,必须删除ViewManager中重写的getExportedCustomDirectEventTypeConstants方法,手动注册会覆盖自动生成的绑定配置,导致事件无法触发。

2. receiveEvent参数说明

RCTModernEventEmitter的receiveEvent方法各参数正确取值如下:

  • 第一个int参数:渲染平面surfaceId,不是视图id,通过UIManagerHelper.getSurfaceId(当前视图)获取
  • 第二个int参数:目标视图的reactTag,直接调用视图本身的getId()方法获取
  • 第三个String参数:事件名,和spec中声明的事件属性名完全一致,此处填"onClickHandler"
  • 第四个boolean参数:canCoalesceEvent事件合并开关,点击属于离散交互事件,传false避免事件被合并丢失
  • 第五个int参数:customCoalesceKey自定义合并key,无自定义合并逻辑传0即可
  • 第六个参数:事件数据Map,字段必须和spec中定义的完全匹配,原代码传message字段和spec的value不匹配,JS侧无法读取
  • 第七个int参数:category事件分类,普通点击事件传1即可

3. 修正原生事件发送代码

import com.facebook.react.uimanager.UIManagerHelper;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.RCTModernEventEmitter;
// 其他原有导入保持不变

public class MyButtonView extends androidx.appcompat.widget.AppCompatButton {

    public MyButtonView(Context context) {
        super(context);
        configureViews();
    }

    private void configureViews(){
        setBackgroundColor(Color.YELLOW);
        setOnClickListener(view -> {
            onReceiveNativeEvent();
        });
    }

    public void onReceiveNativeEvent() {
        WritableMap event = Arguments.createMap();
        // 字段名必须和spec定义的value一致
        event.putString("value", "MyMessage");
        ReactContext reactContext = (ReactContext)getContext();
        int surfaceId = UIManagerHelper.getSurfaceId(this);
        int viewTag = getId();
        reactContext.getJSModule(RCTModernEventEmitter.class)
                .receiveEvent(
                        surfaceId,
                        viewTag,
                        "onClickHandler",
                        false,
                        0,
                        event,
                        1
                );
    }
}

更推荐使用Fabric标准的EventDispatcher方式发送事件,兼容性更好:

import com.facebook.react.uimanager.events.EventDispatcher;
// 省略其他导入
public void onReceiveNativeEvent() {
    WritableMap event = Arguments.createMap();
    event.putString("value", "MyMessage");
    ReactContext reactContext = (ReactContext) getContext();
    EventDispatcher dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, getId());
    int surfaceId = UIManagerHelper.getSurfaceId(this);
    if (dispatcher != null) {
        dispatcher.dispatchEvent(new Event(surfaceId, getId()) {
            @Override
            public String getEventName() {
                return "onClickHandler";
            }

            @Nullable
            @Override
            protected WritableMap getEventData() {
                return event;
            }
        });
    }
}

iOS 端 Fabric 组件事件实现

iOS端Fabric架构下事件不需要通过RCT_EXPORT_VIEW_PROPERTY手动导出,codegen会根据spec自动生成事件绑定逻辑,实现步骤如下:

  1. 执行codegen后会自动生成MyButtonViewViewProtocol.h头文件,自定义组件直接遵守该协议即可,无需手动声明事件属性:
// MyButtonView.h
#import <React/RCTViewComponentView.h>
#import "MyButtonViewViewProtocol.h"

NS_ASSUME_NONNULL_BEGIN

@interface MyButtonView : RCTViewComponentView <MyButtonViewViewProtocol>
@end

NS_ASSUME_NONNULL_END

注意:Fabric组件必须继承RCTViewComponentView,不能直接继承旧架构的UIView子类,否则事件绑定失效。

  1. 在点击回调中直接调用自动生成的事件block传值,字段保持和spec定义一致:
// MyButtonView.mm
#import "MyButtonView.h"

@implementation MyButtonView

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = [UIColor yellowColor];
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap)];
        [self addGestureRecognizer:tap];
    }
    return self;
}

- (void)handleTap {
    if (self.onClickHandler) {
        self.onClickHandler(@{@"value": @"MyMessage"});
    }
}

@end

JS侧使用验证

直接给组件传入对应事件属性即可收到原生回调:

import MyButtonView from './MyButtonView';

<MyButtonView
  text="测试按钮"
  style={{width: 120, height: 44}}
  onClickHandler={(e) => {
    console.log('收到原生点击事件:', e.nativeEvent.value);
  }}
/>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 16:06:25