React Native原生与JS层交互

React Native原生与JS层交互
最新回答
一枝沈荼

2023-04-16 04:29:10

React Native通过精心设计的桥接机制实现原生与JS层的交互,主要分为属性传递、方法调用和事件通信三种核心方式。以下是具体实现原理及代码示例的详细解析:

一、原生向JS层传参1. 初始化参数传递(initialProperties)

通过RCTRootView的初始化参数将原生数据注入JS环境,适用于应用启动时的静态配置:

// 原生端(Objective-C)NSDictionary *props = @{@"images": @[@"
http://foo.com/bar1.png"
]};RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"MyApp" initialProperties:props launchOptions:nil];// JS端class MyComponent extends Component { render() { // 通过this.props访问原生传递的数据 return this.props.images.map(uri => <Image source={{uri}} />); }}

关键点

  • 参数必须是NSDictionary类型
  • JS端通过this.props统一访问
  • 仅在初始化时生效,后续更新需用appProperties
2. 动态属性更新(appProperties)

通过修改RCTRootView.appProperties触发JS组件重新渲染:

// 原生端更新属性(必须在主线程)dispatch_async(dispatch_get_main_queue(), ^{ rootView.appProperties = @{@"images": @[@"new_url.png"]};});

注意事项

  • 属性变更会触发JS组件的componentDidUpdate生命周期
  • 内部采用浅比较判断是否需要重渲染
二、JS调用原生方法1. 模块导出机制

通过实现RCTBridgeModule协议暴露原生功能:

// CalendarManager.h#import <RCTBridgeModule.h>@interface CalendarManager : NSObject<RCTBridgeModule>@end// CalendarManager.m@implementation CalendarManagerRCT_EXPORT_MODULE(); // 默认使用类名作为JS模块名RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location){ // 原生端实现 NSLog(@"Event: %@ at %@", name, location);}@end// JS端调用import { NativeModules } from 'react-native';const { CalendarManager } = NativeModules;CalendarManager.addEvent('Birthday', 'Beijing');2. 参数类型转换

支持JSON基础类型及RCTConvert扩展类型:

// 支持复杂参数类型RCT_EXPORT_METHOD(processEvent:(NSDictionary *)event){ NSDate *date = [RCTConvert NSDate:event[@"date"]]; NSArray *items = [RCTConvert NSArray:event[@"items"]];}3. 回调机制

通过RCTResponseSenderBlock实现异步返回:

RCT_EXPORT_METHOD(findEvents:(RCTResponseSenderBlock)callback){ NSArray *events = @[@"Event1", @"Event2"]; callback(@[[NSNull null], events]); // 参数格式: [error, result]}// JS端处理回调CalendarManager.findEvents((error, events) => { if (!error) console.log(events);});三、原生向JS发送事件

通过事件分发器实现主动通信:

// 原生端发送事件- (void)sendDataToJS{ [self.bridge.eventDispatcher sendAppEventWithName:@"DataUpdate" body:@{@"key": @"value"}];}// JS端订阅事件import { NativeEventEmitter, NativeModules } from 'react-native';const { CalendarManager } = NativeModules;const emitter = new NativeEventEmitter(CalendarManager);const subscription = emitter.addListener('DataUpdate', (data) => { console.log(data.key); // 输出: "value"});// 组件卸载时移除监听componentWillUnmount() { subscription.remove();}四、通信机制原理
  1. 桥接层架构

    JS运行在JavaScriptCore引擎中

    原生与JS通过RCTBridge进行消息序列化/反序列化

    采用JSON格式进行数据传输

  2. 线程模型

    JS → 原生:默认在JS线程发起,原生方法在原生线程执行

    原生 → JS:事件回调在JS线程执行

  3. 性能优化

    批量消息传输减少IPC次数

    预加载模块减少初始化开销

    异步回调避免阻塞

五、最佳实践建议
  1. 数据流管理

    简单配置使用initialProperties

    动态更新使用appProperties+状态管理(如Redux)

    复杂交互采用事件订阅模式

  2. 错误处理

    // 完善的回调处理CalendarManager.doSomething((error, result) => { if (error) { Alert.alert('Error', error.message); } else { // 处理结果 }});
  3. 类型安全

    使用TypeScript定义原生模块接口

    interface CalendarManager { addEvent(name: string, location: string): void; findEvents(callback: (error?: Error, events?: string[]) => void): void;}
  4. 调试技巧

    在Chrome开发者工具中查看桥接日志

    使用RCT_EXPORT_METHOD的__DEV__条件编译

这种分层设计既保持了跨平台开发的灵活性,又通过严格的类型系统和线程模型确保了稳定性,是React Native实现高性能混合开发的关键所在。