执行 expo init AwesomeProject 的时候需要在普通命令行下执行,不要用 git bash。
不要使用 chocolatey 安装 node,有图为证:
npx react-native init 无反应:
abd devices offline
重新打开 "USB调试" 即可。
报错 Package signatures do not match the previously installed version
com.android.ddmlib.InstallException: INSTALL_FAILED_UPDATE_INCOMPATIBLE: Package signatures do not match the previously installed version
卸载应用,重新跑命令:
"设置" → "应用和服务" → Application Name → 卸载,然后跑命令:
npx react-native run-android
警告 failed to connect to development server using adb reverse react native
运行命令:
adb reverse tcp:8081 tcp:8081
全局安装 react-devtools 注意:
推荐使用 npm 安装,而不用 yarn:
npm install -g react-devtools
使用 react-devtools 调试 rn 需注意:
除了跑命令 react-devtools ,还应执行一下命令(更正端口号):
adb reverse tcp:8097 tcp:8097
使用模拟器调试 rn:
- 连接模拟器:
adb connect addr:port
- 查看连接是否成功
adb devices
- 跑项目
npx react-native run-android
使用 adb 连接蓝叠:www.cnblogs.com/rogunt/p/13…
Image
当你使用@2x和@3x图时,也只需要:
<Image source={require('./img/check.png')} />
这样它就会自己识别机器去匹配相应的图片。
动态引图片写法注意:
// GOOD
<Image source={require('./my-icon.png')} />;
// BAD
var icon = this.props.active
? 'my-icon-active'
: 'my-icon-inactive';
<Image source={require('./' + icon + '.png')} />;
// GOOD
var icon = this.props.active
? require('./my-icon-active.png')
: require('./my-icon-inactive.png');
<Image source={icon} />;
使用静态图片它会自动适应宽高,使用网络图片则需要自己手动设置宽高。
背景图片使用 ImageBackground:
<ImageBackground source={require('./xx.jpg')} style={{width: 300, height: 200}}>
<Text>Inside</Text>
</ImageBackground>
absolute 局中:
.foo {
position: 'absolute';
top: -10;
marginHorizontal: 'auto';
}
react navigation:
api 整理:
navigation.navigate 指定跳转页
navigation.goBack 返回上一页
navigation.push 将路由 push 到 history 里,可相同页面跳多次
navigation.popToTop 弹出所有路由,直到第一个路由
使用 createNavigationContainerRef 来进行 navigation 操作:
参考:reactnavigation.org/docs/naviga…
Deep Linking
什么是 Deep Linking?
rn 的原生事件发射器(EventEmitter):
import { DeviceEventEmitter } from 'react-native'
// 常用 api
DeviceEventEmitter.emit(xx)
DeviceEventEmitter.addListener(xx, callback)
DeviceEventEmitter.removeAllListeners(xx)
rn 调用 Android 原生方法:
参考:www.jianshu.com/p/27d87c616…
Execution failed for task ':app:checkDebugAarMetadata'
vim ./android/build.gradle
repositories 下加个 jcenter(),allprojects.repositories 下也加个 jcenter()
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
buildToolsVersion = "30.0.2"
minSdkVersion = 21
compileSdkVersion = 30
targetSdkVersion = 30
ndkVersion = "21.4.7075529"
}
repositories {
google()
mavenCentral()
jcenter()
}
dependencies {
classpath("com.android.tools.build:gradle:4.2.2")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
mavenCentral()
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android")
}
maven {
// Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist")
}
jcenter()
google()
maven { url 'https://www.jitpack.io' }
}
}
参考:stackoverflow.com/questions/6…
react-native-swiper 使用异步数据会使得左右按钮失去作用?
虽然不知道为什么,但要在 外层添加判断:list?.length > 0 再渲染 Swiper。
安卓无法显示 gif:
// 需要与 react native 版本对应的 fresco 才可以
// 查看版本可以通过:
// gradlew :app:androidDependencies
implementation 'com.facebook.fresco:animated-gif:2.5.0'
react-navigation中 push, navigate, goback, pop 的区别:
TextInput 文字显示不全:
paddingVertical: 0
图片显示不全:
resizeMode 设置为 contain
页面 navigate 并不会销毁,只有 back 才会销毁
在进入下一页时,useEffect 的 return 函数并不会执行,其只有在 back(返回上一页) 时才会执行。这小可爱跟 react 和 小程序的套路完全不一样好吧,react 和 小程序在进入下一页,都是会执行销毁操作的,这个小可爱竟然还需要 useIsFocused 来 hack,佛了,佛了。
react-native 的 useIsFocused 销毁页面执行时机在下一个页面的 show 之后(坑!!!)
比方说,两个页面,分别都有如下代码:
// A
useEffect(() => {
if (isFocused) {
console.log('A ----------> show')
}
return () => {
console.log('A ----------> destory')
}
}, [isFocused])
// B
useEffect(() => {
if (isFocused) {
console.log('B ----------> show')
}
return () => {
console.log('B ----------> destory')
}
}, [isFocused])
那么,当从 A navigate B, 然后 B navigate 其他页面,会有如下打印:
A ----------> show
B ----------> show
A ----------> destory
B ----------> destory
这个真的是很扑街,下个页面的 show 竟在上个页面的 destory 之前,因此,removeAllListeners 操作最好指定清除事件名,不然所有都清除很容易把下个页面的全清了,如果下个页面有 listener 将无法顺利监听到!!!
DeviceEventEmitter 的 removeSubscription 已弃用的替代方案:
remove,yyds
View 的 measure 方法:
viewRef.current?.measure((x, y, width, height, pageX, pageY) => {
// width 宽
// height 高
// pageX 离左边的距离
// pageY 离顶部的距离
console.log('measure: ', x, y, width, height, pageX, pageY)
})
TouchableWithoutFeedback 有阻止父层事件功效:
<TouchableOpacity onPress={handleParentPress}>
<TouchableWithoutFeedback onPress={handlePress}></TouchableWithoutFeedback>
</TouchableOpacity>
以上,调用 handlePress 时,不会触发 handleParentPress
多图加载过慢原因:
在多图加载的场景里,经过实践,iOS 不管怎么折腾,表现都比较好,但是 Android 就容易出幺蛾子。下面我们就详细说说 Android 端如何优化图片。
在一些场景里,Android 会内存爆涨,帧率直接降为个位数。这种场景往往是小尺寸 Image 容器加载了特别大的图片,比如说 100x100 的容器加载 1000x1000 的图片,内存爆炸的原因就是上面说的原因。
那么这种问题怎么解决呢?Image 有个 resizeMethod 属性,就是解决 Android 图片内存暴涨的问题。当图片实际尺寸和容器样式尺寸不一致时,决定以怎样的策略来调整图片的尺寸。
resize:小容器加载大图的场景就应该用这个属性。原理是在图片解码之前,会用算法对其在内存中的数据进行修改,一般图片大小大概会缩减为原图的 1/8。scale:不改变图片字节大小,通过缩放来修改图片宽高。因为有硬件加速,所以加载速度会更快一些。auto:文档上说是通过启发式算法自动切换 resize 和 scale 属性。这个启发式算法非常误导人,第一眼看上去还以为是会对比容器尺寸和图片尺寸采用不同策略。但我看了一下源码,它只是单纯的判断图片路径,如果是本地图片,就会用 resize,其他都是 scale 属性,所以 http 图片都是 scale 的,我们还得根据具体场景手动控制。
错误: 程序包android.support.annotation不存在import android.support.annotation.Nullable;
更改对应的java文件:
- import android.support.annotation.Nullable;
+ import androidx.annotation.Nullable;
解决 Modal 之上不能 toast
使用了 Modal ,toast 的无法覆盖在 Modal 之上,导致 toast 被遮罩挡住了,解决:
在 Modal 下方添加 RootSiblingParent 即可
<Modal>
<RootSiblingParent>...</RootSiblingParent>
</Modal>
react-native-navigation navigate机制
调用 navigate 以后,会 push 一层路由,当重复调用时,能进行复用,举个例子:
A → B → C → B
以上第二次跳 B 时,能复用上次的 B,并且弹出后面的路由(C),所以当 B 返回是,会返回到 A。