402v /posts/react-nativeru-men-shi-li-jiao-cheng-kai-shi-kai-fa
React Native入门实例教程 - 开始开发
最近一段时间在学习和实践React Native,做一些有趣有用总结和大家分享。这个系列文章可以在这里找到。
入口文件
React Native项目初始化时默认的入口文件是index.ios.js,根据我们在React Native入门实例教程 - 从现有项目迁移中的配置,运行项目后会将index.ios.js以及所以来的JS文件打包成index.ios.bundle。
通过Node.js Server访问这个bundle,就可以得到所需要的视图。
了解有关这个调试Server以及React Native Debug相关内容,可以访问React Native入门实例教程 - 调试系统
视图构建
RCTBridge - 桥接
OCBridge是利用JavascriptCore直接调用JS代码的。OC层实现这个类的是RCTBridge,目前的代码是使用RCTContextExecutor作为具体的执行者。JavascriptCore是iOS7才开放的接口,不过目前的代码还有另外一套RCTWebViewExecutor,里面用的是通过UIWebView调用JS,可能是为了以后兼容旧版本的iOS。使用JavascriptCore最显而易见的优势就是,整个执行过程都可以在后台线程执行,事实上RCTContextExecutor单独开了一个名为「com.facebook.React.JavaScript」的线程,供自己使用。
RCTRootView - 视图容器
Native代码中通过RCTRootView这个类引用JS视图,示例代码如下:
NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle"];
// For production use, this `NSURL` could instead point to a pre-bundled file on disk:
//
// NSURL *jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
//
// To generate that file, run the curl command and add the output to your main Xcode build target:
//
// curl http://localhost:8081/index.ios.bundle -o main.jsbundle
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName: @"SampleApp"
initialProperties:nil
launchOptions:nil];
上述代码中是通过访问server localhost:8081来实现加载jsbundle,也可以直接将打包好的jsbundle文件集成在项目资源中,然后从mainBundle直接引用。这样做的问题是每次js代码变动都需要更新jsbundle并重新编译。这种方式通常用于App发布时默认资源包的集成。jsbundle的详细创建方式参见React Native入门实例教程 - 项目打包发布
目录组织
如果项目采用Native与React Native混编的方式,那么入口文件index.ios.js可能不止一个,每个React Native模块都会有一个入口文件。我的做法是将所有JS代码分模块放在与React Native开发环境同级的ReactComponents目录下,例如:
- ReactComponents
- CustomModule1
- custom1.ios.js
- custom1.android.js
- imgs/
- CustomModule2
- custom2.ios.js
- custom2.android.js
- imgs/
由于调试server的根目录指向React Native的环境目录(node_modules、package.json等文件所在的目录),因此入口文件访问的路径为:http://localhost:8081/ReactComponents/CustomModule1/custom1.ios.bundle。注意是文件后缀是bundle而不是js。
容器视图
在大型项目中解耦第三方库和主项目依赖是非常重要的一件事情,它能让你的项目架构更清晰,适应更多的变化。为了解耦React Native的源码和你的项目,可以定义如ReactView和ReactViewController这样的类,将RCTRootView等相关逻辑封装进去,甚至添加自定义的导航控制器。
Native Modules
对于一些Native项目已有的控件,我们希望也能通过JS代码来访问他们,React Native已经给我们提供了成熟的转换方法,实现起来非常简单。
转换方法
- 实现
RCTBridgeModule协议;
// CalendarManager.h
#import "RCTBridgeModule.h"
@interface CalendarManager : NSObject <RCTBridgeModule>
@end
- 添加
RCT_EXPORT_MODULE()宏,将当前模块导出;
// CalendarManager.m
@implementation CalendarManager
RCT_EXPORT_MODULE();
@end
- 将需要暴露给JS的方法用
RCT_EXPORT_METHOD包起来。
RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
{
RCTLogInfo(@"Pretending to create an event %@ at %@", name, location);
}
- 接下来就可以在JS代码中访问这个module了。
var CalendarManager = require('react-native').NativeModules.CalendarManager;
CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey');
值得注意的问题
定义navtive module的一个问题是无法访问它的类方法,或者控制初始化方法,感觉还是不灵活。
比如在一个Native的VC中嵌入ReactView,这个ReactView无法访问到它的VC,这样会给我们的设计上带来一些困难。
RCTConvert
RCT_EXPORT_METHOD的参数支持标准的JSON类型:
- string (NSString)
- number (NSInteger, float, double, CGFloat, NSNumber)
- boolean (BOOL, NSNumber)
- array (NSArray) of any types from this list
- map (NSDictionary) with string keys and values of any type from this list
- function (RCTResponseSenderBlock)
自定义的类型如果想在JS中作为参数需要先做convert。
automatic type conversion feature
##小技巧
- 将方法标记成deprecated
- JSONKit在64位上有问题,React Native在加载bridge过程中解析JSON时优先会用JSONKit,因此暴露了这个问题,更新最新支持64位的JSONKit解决此问题。
- JSX陷阱|JSX与HTML的区别
- Swift类获取OC Runtime:
@objc(CalendarManager)
评论 · 0
还没有评论。