记录下自己遇到的…
react-native 须知
React
的每个组件里,必须import React
1 | import React from 'react'; |
因为组件内部隐式的使用了React
,比如jsx
语法等
自定义组件
分为函数式组件和 class 组件,我们一般使用 class 组件。
函数式组件:
1
2
3
4/* 接受的参数是 props */
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}class 组件:
1
2
3
4
5class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
注意: 组件名称必须以大写字母开头。
组件触发事件
1 | class Toggle extends React.Component { |
推荐使用方式2,简单明了,且没有副作用。详解请参看 官方文档
遍历渲染组件:
jsx
中只能写表达式,不能写多行语句,所以不能写 if else
、 for
… 最佳循环写法是使用 map
函数
1 | <View> |
注意:
key
必须在其兄弟节点中是唯一的,而非全局唯一- 并不建议使用元素在数组中的索引作为
key
。若数组没有重排,该方法效果不错,但若重排了(比如数组内重新排序、数组头部插入新元素),那样,内容相同的元素他们的key
并不相同,React
就会都重新渲染,而且相同key
元素也有可能以意想不到的方式混淆和更新。详情参考 这儿
Ref :
分为 String 类型 和 回调函数类型,推荐使用回调函数类型,React
官方称 String 类型已过时并在未来版本可能被删除。还有一种是传递 createRef()
创建的 ref
属性 ,个人感觉不太方便,具体请看标题的超链接。
- 当
ref
属性被用于一个普通的HTML
元素时,回调函数将接收底层DOM
元素作为它的参数 - 当
ref
属性被用于一个自定义类组件时,回调函数将接收 该组件已挂载的实例 作为它的参数1
2
3
4
5
6
7
8
9
10
11
12
13class AutoFocusTextInput extends React.Component {
componentDidMount() {
this.textInput.focusTextInput();
}
render() {
return (
<CustomTextInput
// input是CustomTextInput的实例
ref={(input) => { this.textInput = input; }} />
);
}
}
注意: ref
只能用于 class 组件 ,不能用于 函数式组件, 因为函数式组件没有实例。
PureComponent 与 shouldComponentUpdate(nextProps, nextState)
shouldComponentUpdate(nextProps, nextState)
:
- 不在初始化渲染或当使用
forceUpdate()
时被调用。当接收到新属性或状态时,shouldComponentUpdate()
在render()
前被调用。 - 默认返回
true
,表示重新渲染。若我们想要在props
、state
中的某些值变化时不重新渲染,通过与nextProps
、nextState
比较实现逻辑,在你想要的地方返回false
PureComponent
:
在某些场景下你可以使用 React.PureComponent
来提升性能。与 React.Component
几乎完全相同,但 React.PureComponent
通过 prop
和 state
的浅对比来实现 shouldComponentUpate()
更多查看 这儿
react-native 调试
在调试网页的时候我们使用Chrome Devtool
,它上面有些面板非常好用,我最常用的有: Source
、Console
、Elements
、NetWork
,现在我们调试 React Native
的 app 。我们分别使用以下工具来操作上面各项的调试:
Source
、Console
: 模拟器上打开Debug JS Remotely
, 就会在 http://localhost:8081/debugger-ui 上打开调试页面,将这个页面在Chrome
中打开,然后就可以跟调试网页一样,可惜只能调试这两个面板,无法监控Network
Elements
; 安装react-devtools
, 并在模拟器上打开Toggle Inspector
配合使用。具体参考 官方文档NetWork
: 前面说到Debug JS Remotely
没法监控Network
, 这个问题官方还没解决,可以查看这个 issue。当然聪明人很多,有大佬开发了 reactotron ,使用的话:- 需要安装这个软件、项目中安装依赖
yarn add reactotron-react-native -D
添加配置文件
ReactotronConfig.js
并引入到入门文件——index.js
/App.js
首行即可具体的请参考 官方链接 或 掘金的这篇文章。
注意: 如果要监听Android
模拟器的请求,需要运行adb reverse tcp:9090 tcp:9090
(9090是Reactotron
的默认端口) , 并且在ReactotronConfig.js
中配置1
Reactotron.configure({ host: '宿主机ip' }).connect()
详情参考此issue
- 需要安装这个软件、项目中安装依赖
开启自动刷新:真机或者模拟器中Enable Live Reload
和Enable Hot Reloading
同时打开,下面的情况需要重新编译:
- 增加了新的资源(比如给
iOS
的Images.xcassets或是Andorid
的res/drawable文件夹添加了图片) - 更改了任何的原生代码(objective-c/swift/java)
同时启动两个项目:需要同时启动两个packger与模拟器
同时启动两个
packger
:1
react-native start --port 端口号
启动两个模拟器之后
1
2
3react-native run-android --deviceId [device_id]
device_id可以通过下面的命令进行查看:
adb devices
tip: 其他常用 adb
命令
1 | # 进入模拟器shell命令 |
- 如果是两个模拟器,和电脑在同一个wifi下,那分别在 dev-setting => Debug server host & port for device 下添加:电脑ip:port 。设置之后按两次R重新加载
bundle
即可。
注意:两个模拟器都必须指定端口,即使一个packger
是默认端口。
疑问: 同时启动 ios 和 android 模拟器经常有一个会没反应,原因未知
react-native 打包
官方文档介绍的很详细,下面只是些临时用作测试的打包
android
不使用签名的简单打包:
1 | cd android |
react-native 常见错误
Native module 模块名 tried to override 模块名 for module name xxx. If this was your intention, set canOverrideExistingModule=true
原因: 通常重复执行 react-link
引起的,会在 MainApplication.java
、 build.gradle
、 settings.gradle
里重复导入包。这是 facebook 的官方bug,详情可以看 stackoverflow
解决方法: 检查 MainApplication.java
,删除重复出现的包 。一般是在两个地方重复,一是 import
,二是 protected List<ReactPackage> getPackages()
里面。 build.gradle
、 settings.gradle
里虽然也重复了,但不会报错,项目也可以正常跑起来。
注意: 有些包虽然你执行了 react-native link
, 但并不会正确引入到原生代码里。比如说:react-native-permissions,需要单独执行 react-native link react-native-permissions
。具体情况还是多看看人家的 README
react-native-scrollable-tab-view 有时候不显示内容,升级到^0.7.4即可
genymotion 模拟器滑动时老切换到搜索页面,并出现00003。关闭有道词典的划词翻译即可。
android打包错误
本来好好地项目打包出错,比如这样的错误::app:packageDebug
,或者说什么解压不了文件什么的,可以尝试用下面的语句:
1 | cd android |
清理缓存后重新打包
权限问题
官方对
android
出了 PermissionsAndroid API,刚开始检测 相机权限 ,无论我在 app 中给没给相机权限,这个 API 给我返回的结果都是有权限。原因:
Android 6.0
之前的版本只要是在AndroidManifest.xml
申明的权限这个 API 都会返回有权限。解决方法: 需要修改
build.gradle
里的targetSdkVersion
为 23 才可以。注意: 需要卸载原来的 app 重新装。Ios
的权限判断使用 react-native-permissions , 其实android
也可以使用这个,很方便。下面有个 demo:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19_requestCameraIosPermission = async () => {
let permitStr = 'camera';
let response = await Permissions.check(permitStr);
if (response === 'undetermined') { /* 之前没有弹出来过权限申请 */
let requestResult = await Permissions.request(permitStr);
return requestResult === 'authorized';
} else if (response !== 'authorized') {
Alert.alert(
'权限提醒',
'请到设置中开启INKubator Pay的相机权限',
[
{ text: 'Ok', onPress: Permissions.openSettings }, /* 跳转到IOS系统的权限设置 */
{ text: 'Cancel', style: 'cancel'}
]
);
return false;
}
return true;
};
react-native 杂谈
Android
api与版本号对应关系
react native
要求我们安装的 sdk
都是 api 23 的对应版本,这个对应的版本号是 Andrid 6.0
,其他的对应关系请参考 这儿
require
只能使用静态字符串,因为它是在编译期执行,而不是运行期。js执行过程:
React Native
从0.5.0版本开始已经内置Babel
转换器
Android Studios 常用快捷键
打开 andorid studio
,会默认根据 gradle
同步项目。同步完成后才可以 Build 与 Run,一般可以直接 Run
- 快速打开某一个文件: command + shift + O
- 根据
gradle
同步项目:File -> Sync Project with Gradle Files
- Run: control + R
XCode 常用快捷键
- 快速打开某一个文件: command + shift + O
- 返回至上一次光标位置: control + command + ← , control + command + →
- 快速查看当前class的方法: control + 6