react-native开发中遇到的坑

样式的坑


1、 无 border: none 样式属性;
2、 StyleSheet.create() 创建了一个样式,在组件上使用时仅仅引用了一个id,所以如果你打印styles.name,则会返回一个数字id;

  • 创建一个样式表,就可以使得我们后续更容易通过ID来引用样式,而不是每次都创建一个新的对象。
  • 它还使得样式只会在JavaScript和原生之间传递一次,随后的过程都可以只传递一个ID(这个优化还未实现)。

密钥库文件问题


在使用react-native-amap3d组件时,需要注册高德key,出现以下问题:

[keytool 错误: java.lang.Exception: 密钥库文件不存在: keystore]

参考地址:https://blog.csdn.net/Newsolider2012/article/details/52401735

第一步、生成keystore文件

keytool属于java jdk的一个工具,我们可以利用这个去生成密钥文件;

  1. 打开cmd, 使用命令cd 你的java安装目录/java/jdk/bin,进入keytool可执行文件的路径;
  2. 执行keytool -genkey -alias key文件别名 -keyalg RSA -validity 20000 -keystore geom.keystore,会出现接下来的界面:

    在bin目录下会生成对应的.keystore文件,此文件就是你的签名文件;

第二步、在项目中应用keystore

打开你的Android项目的build.gradle,将keystore文件绑定到项目中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
signingConfigs {
release {
keyAlias 'geom'
keyPassword 'lfreformer'
storeFile file('E:/GeomDebug/android/keystores/geom.keystore')
storePassword 'lfreformer'
}
debug {
keyAlias 'geom'
keyPassword 'lfreformer'
storeFile file('E:/GeomDebug/android/keystores/geom.keystore')
storePassword 'lfreformer'
}
}
}

第三步、获取KeyStore指纹信息

打开Android studio 的控制台;执行命令:
keytool -list -v -keystore E:\GeomDebug\android\keystores\geom.keystore(这儿需要你替换成自己的keystore文件路径)
注意:最后是你keystore文件存放位置;最后获取结果:

其中SHA1值就是需要的在高德地图中填写的内容。

模拟数据


由于项目开发过程中前端独立开发阶段需要自己模拟本地数据,所以就引出一个问题,react-native的模拟数据放置在哪,如何请求。
其实react-native启动时会在项目根目录默认开一个端口号为8081的server,所以只需将mock数据放置在项目根目录进行请求即可。
我的模拟数据目录:

请求示例:

1
fetch('http://localhost:8081/mock/xx.json').then(...)

Api方式动态添加元素


参考:react-native-root-siblings

在开发过程中会遇到自定义toastalert等需要通过api方式(eg: Toast.show())全局显示的组件,这个时候要动态添加组件,并且必须是全局组件的属性,在react-native中如何实现,这个时候需要用到AppRegistrysetWrapperComponentProvider方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import  React, { Component } from  'react';
import { View, Text, AppRegistry } from 'react-native';

AppRegistry.setWrapperComponentProvider(function() {
return class extends Component {
constructor(props) {
super(props);
}

render() {
return (
<View style={{flex: 1}}>
{this.props.children}
<View
style={{
width: 200,
height: 500,
backgroundColor: 'red',
position: 'absolute',
zIndex: 1000,
top: 45,
left: 0
}}
/>
</View>
)
}
}
})

注意:

  1. AppRegistry.setWrapperComponentProvider 不可用在组件生命周期内,必须全局/模块中使用;
  2. return的组件中必须包裹{this.props.children},这个子组件代表你每页的组件,而内部包含的View组件就是你动态添加的组件;

Android端双击物理返回键退出应用


api: BackHandler; 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
export default function (WrappedComponent) {
return class extends Component {
constructor(props) {
super(props);
this._onBackAndroid = this._onBackAndroid.bind(this);
}

componentWillMount(){
BackHandler.addEventListener('hardwareBackPress', this._onBackAndroid);
}

componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this._onBackAndroid);
}

render() {
return (
<WrappedComponent {...this.props} backHandler={this._onBackAndroid} />
)
}

_onBackAndroid() {
if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {
//最近2秒内按过back键,可以退出应用。
return false;
}

this.lastBackPressed = Date.now();

ToastAndroid.show('再按一次退出应用', ToastAndroid.SHORT);

return true;
}
}
}

示例为react高阶函数组件,可包裹用于任意组件;
存在问题:
首页组件不会触发componentWillUnmount生命周期,所以会导致在首页后打开的任意页面物理返回键均会触发“再按一次退出应用”,在react-navigation中,修改为如下方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
componentDidMount() {
this.getParkData();

this.didFocusSubscription = this.props.navigation.addListener(
'didFocus',
payload => {
BackHandler.addEventListener('hardwareBackPress', this.props.backHandler);
this.getStorage().then(data => {
if (data) {
data = JSON.parse(data);
AsyncStorage.removeItem('selectPark');
this.locate(data, this.showInfoWindow.bind(this, data));
}
})
}
);

this.willBlurSubscription = this.props.navigation.addListener(
'willBlur',
payload => {
BackHandler.removeEventListener('hardwareBackPress', this.props.backHandler);
}
);
}

componentWillUnmount() {
if (this.didFocusSubscription) {
this.didFocusSubscription.remove();
}

if (this.willBlurSubscription) {
this.willBlurSubscription.remove();
}
}

以上通过监听react-navigation提供的事件进行BackHandler的处理;

修改打包后应用名


默认应用名会是应用初始化时的文件名;修改方式:

  1. 进入android/app/src/main/AndroidManifest.xml;
  2. 找到android:label="@string/app_name",这个就代表的是应用名(引用第三步文件内的值);
  3. 进入android/app/src/main/res/valuse/strings.xml
  4. 修改如下代码:
    1
    2
    3
    <resources>
    <string name="app_name">你的APP名称</string>
    </resources>