前段时间粗糙的研究了下React Native,写了两篇集成文章(幸好写了文章,时间长了有些东西还真忘了集成一,集成二),后面断断续续研究了下,因为没有实际项目运用,感觉学习的不连贯。这两个星期用RN技术复刻一个旧的项目,方才让学到的东西有了使用,两星期就正式上线了。不过这其中可以说是一步一坑,不过最终都解决了。因为时间紧,有些没来得错误没来得及截图,不过这里会记录一些关键的坑和要点,希望对大家有所帮助。
1.编译软件推荐 —> Visual Studio Code,一开始尝试用Sublime(写H5的时候一直用的),但是发现好别扭,用VS还是挺顺手,推荐
2.在现有项目集成RN,可以参考我的集成文章 –集成一,集成二)
真机测试的时候我们都用的本地局域网路径,启动RN服务,如:
但是上线的时候,我们要打包,所以不能这样访问,要做以下操作:
1.再你的RN文件夹下新建bundle文件夹
2.终端cd到RN目录
3.执行命令 react-native bundle --entry-file ./App.js --bundle-output ./bundle/index.ios.jsbundle --platform ios --assets-dest ./bundle --dev
注*:.App.js 你的主JS名称,自行修改
4.build下文件全部拖到Xcode工程
5.每次JS有修改,都要重新执行命令
然后如下访问:
1.快速入门-准备工作
2.快速入门-添加热更新功能
3.快速入门-发布应用
4.常见问题
1、打开终端,cd 当前RN目录
2、输入并运行 npm install react-native-deprecated-custom-components --save
3、在使用到Navigator组件时换成 :NavigationExperimental.Navigator即可(如果没报错,这句可以忽略)
然后再JS里面调用如:this.props.clickID 来获取对应参数
SRRNCommonManager类(继承NSObject),并实现导入以下代码
1.#import
2.协议
3.原生代码实现
//为了实现RCTBridgeModule协议,需要包含RCT_EXPORT_MODULE()宏。
//这个宏也可以添加一个参数用来指定在Javascript中访问这个模块的名字。
//如果不指定,默认就会使用这个Objective-C类的名字。
RCT_EXPORT_MODULE()
//js跳到原生-调到原生到访确认单
//通过RCT_EXPORT_METHOD()宏声明要给Javascript导出的方法,否则React Native不会导出任何方法。
//方法名,参数可以自定义
RCT_EXPORT_METHOD(pushVisitConfirmation:(NSString *)message type:(NSString *)type)
{
}
4.JS代码实现
//导入
import {
NativeModules
} from 'react-native';
//声明一个参数,格式如下
var SRRNCommonManager = NativeModules.SRRNCommonManager;
//调用
SRRNCommonManager.pushVisitConfirmation(
"参数message",
"参数type"
);
1.写一个继承RCTEventEmitter的类SRActionToJS
2.导入
#import
#import
3.协议
4.原生代码实现
RCT_EXPORT_MODULE();
- (NSArray *)supportedEvents
{
return @[@"EventReminder"]; //必须实现,可以注册多个 原生给JS发送数据
}
//固定格式
- (void)startObserving
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(emitEventInternal:)
name:@"event-emitted"
object:nil];
}
//固定格式
- (void)stopObserving
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
//通知实现,给JS传值
- (void)emitEventInternal:(NSNotification *)notification
{
[self sendEventWithName:@"EventReminder" body:@{@"imageData":notification.object}];
}
//暴露给外部的方法,这里我需要的是base64的图片
+ (void)actionToJSEventReminderReceived:(NSString *)imageData //触发方法 用类方法,对象方法,alloc可能会报错
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"event-emitted" object:imageData];
}
5.JS代码实现
//导入
import {
NativeModules,
DeviceEventEmitter
} from 'react-native';
//声明
var nativeBridge = NativeModules.SRActionToJS;
const SRActionToJSManagerEmitter = new NativeEventEmitter(nativeBridge);
//监听+实现
componentDidMount() { //声明周期,JS加载完成
if (!this.subscription) {
this.subscription = SRActionToJSManagerEmitter.addListener('EventReminder', (result) => {
try {
result.imageData //实现,拿到原生的传值
} catch (error) {
}
});
}
1.shadowHidden: true
隐藏导航栏,如果实现不了,尝试调换代码顺序,对,就是这么神奇
2.给下个页面传值
passProps: {
kHeight: this.props.screenHeight,
kisIos11: this.props.isIos11,
}
//下个页面直接调用:tihs.props.kHeight就可以
RN里面也有类似于原生的监听方法。有个需求是当前值发生变化,要刷新上个页面的数据,这时候用到通知。但是实现的通知方法,只走打印,不走刷新数据的方法。研究了下,可能是发送通知的时机问题,换了下发送的时机,就能正常运行。
//A页面注册监听,'changeData' 触发参数,param收到的传值
componentDidMount() {
this.refreshData(true);
this.subscription = DeviceEventEmitter.addListener('changeData',(param) => {
this.refreshData(true,true) //自行处理事件方法
})
}
componentWillUnmount() {
if (this.subscription) { //注销监听
this.subscription.remove()
this.subscription = null
}
}
//B页面发送通知,如数据改变,需要通知A页面刷新,不能像原生那样直接发通知,我的处理是:
componentWillUnmount() { //页面将要注销,另外,注册了监听,在当前页面要注销
if(this.successLoad){ //用一个全局参数记录是否需要发送通知
DeviceEventEmitter.emit('changeData','参数') //发送监听事件
}
if (this.subscription) { //注销监听
this.subscription.remove()
this.subscription = null
}
}