amandakelake/blog

React+RN开发过程中的一些问题总结(持续更新。。。)

amandakelake opened this issue · 15 comments

写RN的过程中踩过大大小小的坑,有些解决了,有些还等挖掘更好的方案,甚至有些解决不了的就直接绕道了(希望有大神指导一下),也一并记录下来好了,这部分也会持续更新。。。
可惜有些问题解决完就忘了,没记录下来,特别是调试、真机、平台方面的

题外话:有些当初苦苦想破脑袋的坑,踩过后才发现是如此的弱🐔,本来是不应该show出来贻笑大方的,但万一就是有小白也刚好陷入跟我当初一样的思维怪圈呢?所以不怕大家笑话,就一股脑都写下来吧,若干年后回头一看:原来当年我傻的如此可爱,能博得自己一笑,不也挺有意思的么

一、如何解决问题

这里科普一下自己遇到问题的通用解决办法

1、看官方文档,很多问题官方都已经考虑到了,对着关键词搜
这里要吐槽一句,RN的中文文档是真滴烂,推荐看英文文档(看不懂就好好学英语)
2、google (不要百度)
google出来的列表里面,优先看github的issue,其次看stackoverflow,然后才是其他的选项
e3d09196-d76a-469f-9653-953dc2eb5194

3、问同事(一定要再自己google后),问你认识的大神好友
带着清晰的问题,**问题就别问了

4、以上三板斧都解决不了的话,信佛的阿弥陀佛,信基督的阿门吧

二、问题记录

PS:下面的问题全都没有按照顺序或者时间分类,大部分是以前自己随手记录的笔记,就是辛苦一些看文章的小伙伴了,或者可以cmd+F或者ctrl+F直接搜索自己需要的内容

1、RN:子元素宽度问题、位置居中

RN默认使用flex布局,子元素不用设置宽度,会自动拉伸满容器
45667b71-3ed7-46db-90d1-e012388c947a

如果子元素想居中
除了使用父元素的alignItems: 'center'
还是可以使用子元素的alignSelf: 'center'
这样子的话子元素的宽度不再拉伸,会按照实际内容宽度,如下

export default class PopularizeHome extends Component<Props> {
  render() {
    return (
      <View>
        <View style={styles.childContainer}>
          <Text>PopularizeHome</Text>
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  childContainer: {
    // alignSelf: 'center',
    backgroundColor: 'red'
  },
});

29240659-9956-4da3-b58f-047da63750ab

2、RN:使用原生的Navigator时隐藏TarBar底部导航栏

会有小bug,最好是用react-navigation或者react-native-navigation
f6e90656-f5b8-4372-a5b9-324e53413ecc

3、RN:HTTP安全限制

iOS9 & iOS10 HTTP 不能正常使用的解决办法 - iOS前沿 - SegmentFault
46b2ab74-1601-4e9a-9446-937336ae079f
50754b81-27fd-4f0f-b2f6-6f57848886dc

4、React:swiper高度限制

swiper自带的的高度是属性控制,不是样式控制
可以在swiper外面套一层来控制高度

5、React:循环渲染时,onPress事件不需要再把item当做参数

否则会拿不到正确的item值
886e1618-d743-415a-a5ee-7d52e5b2fdc6
bd9af936-ae2a-40e6-90d5-7e7fc20a6163

6、fecth使用formData上传数据

11f82003-de60-4be3-a914-aa9de3735073

7、TextInput右边的padding会超出屏幕

flex:1无法读取宽度,需要计算屏幕宽度
6085bd15-316d-40a9-9bb0-e07c0e3f54c6
e9508e7c-6a15-4206-874c-726f3bc83ff9

8、react-navigation的设置navigationOptions里面读取state的数据和绑定方法

需要记得bind(this)
fa70e3e0-78a6-43b3-995e-7ea56742114c

9、复用input[radio]组件时,ID必须唯一,否则会两个input[radio]之间造成串联,互相影响

1b6ac217-52ea-4750-9f2a-13fdd1cdba4e

10、RN:AsyncStorage本地存储,setItems时要用string,不能用到其他类型

setAsyncStorageIsLaunched() {
    AsyncStorage.setItem('HAS_LAUNCHED',true).then(() => {
      console.log('第一次登录成功',this.getAsyncStorageIsLaunched());
    });
  }

d690b9bd-beb5-41e5-a68a-26ce25e6a563

11、RN: source.uri should not be an empty string

有可能后台真的没有返回图片链接,虽然不是红色错误,黄色warning也很烦,做好三元判断就好了

{card.bank_background ? <Image
  style={styles.itemBgIcon}
  resizeMode="contain"
  source={{ uri: card.bank_background }}
/> : null}

12、对于一些依靠后台数据的地方,做好拿不到数据或者错误数据的准备,给一个默认值,防止报错

比如这里,一个渐变模块,后台如果不给颜色,那就会直接报错
b8009866-a6db-43a4-8416-2faef8233be4

还有一个最常见的情况,数组的渲染,做好多重保险
b11f74a8-9650-4144-82c5-c4c8c29868c8

13、Raw text cannot be used outside of a tag. Not rendering string: ''

{card.status_name && (
  <View style={styles.itemTopRight}>
    <Text style={styles.itemTopRightText}>{card.status_name}</Text>
  </View>
)}

try the !! trick to make sure you only use booleans

{!!card.status_name && (
  <View style={styles.itemTopRight}>
    <Text style={styles.itemTopRightText}>{card.status_name}</Text>
  </View>
)}

Or use the ? : 三元运算符

{card.status_name ? (
  <View style={styles.itemTopRight}>
    <Text style={styles.itemTopRightText}>{card.status_name}</Text>
  </View>
) : null}

14、React Native ListView 需触摸/滑动后才显示的问题,官方Issues:

点这里

// 需要在初始化 ListView 时添加以下参数配置
removeClippedSubviews={false}

15、ListView的问题

4884a83d-91b2-41b9-9b0b-ddae3f8f9806

16、使用FlatList的注意事项

1a27cad1-e885-4dc3-a93e-230ca8ca0d20

17、安卓的物理返回键盘(防止直接退出应用)

监听返回事件,改写
移除组件的时候,移除监听
35667ac4-91fb-4fd9-98c8-a1416cae5b28

18、RN:0.44版本后,Navigator和BackAndroid组件都不存在了

从0.44版本开始,Navigator不再从‘react-native’中引入,而是需要

npm install react-native-deprecated-custom-components –save

并在代码中引入

import { Navigator } from 'react-native-deprecated-custom-components'

同样从0.44版本开始,BackAndroid组件不在出现,而是用BackHandler代替

19、在render函数中中循环修改state,导致最后栈溢出

f0902ea9-4a98-4131-8590-1efead864162
0b69c191-a047-4872-aa66-61f4b06b3976

看下面,是罪魁祸首
应该是定义函数,而不是直接执行
7cb4030a-9f12-4878-9a25-ebd7d1732719

20、开debug模式时load bundle 100% 卡住(未解决),关掉远程debugger就就OK,需要重启电脑解决

WebSocket connection to ‘ws://localhost:8081/debugger-proxy?role=debugger&name=Chrome’ failed: Invalid frame header · Issue #6627 · facebook/react-native · GitHub
React-Native Error: Connection to http://localhost:8081/debugger-proxy?role=client timed out - Stack Overflow

还没解决
RCTModuleData deadlock when running with debugger · Issue #11196 · facebook/react-native · GitHub
RCTBridge required dispatch_sync to load RCTDevLoadingView. This may lead to deadlocks · Issue #16376 · facebook/react-native · GitHub

具体什么情况我也不是很清楚,mac的话,重启电脑就好了(我试验了很多次)

  • 首先需要设置IP和端口,默认端口是8081,手机(模拟器)和电脑在同一个网络中,查询电脑的IP地址。
  • 手动去删除.babelrc隐藏文件,具体文件目录为node_modules/react-deep-force-update/.babelrc
  • 如果是其他版本,那也是需要删除的不过路径已经发生变化了。具体路径:/node_modules/react-native/node_modules/react-transform-hmr/node_modules/react-proxy/node_modules/react-deep-force-update
  • 最后重点 Android项目关闭终端重新执行运行命令,iOS项目也需要关闭服务终端,重新启动packager

21、子组件有复杂的数据和操作,需要父组件触发更新,但不想提升到父组件

使用componentWillReceiveProps增加父组件的标志位,子组件检测到父组件传下来的该标志位的变化时,即可触发更新

componentWillReceiveProps(nextProps) {
    if (nextProps.needUpdatePopularize !== this.props.needUpdatePopularize) {
      this.onRequestData();
      this.requestRank();
    }
  }

22、Task orphaned for request <NSMutableURLRequest: 0x1c4202170>

Unmount images while loading · Issue #12152 · facebook/react-native · GitHub
图片还没完全加载完成的过程中,就触发其他操作,比如页面跳转,这时候又需要unmount 图片,就会出现这些黄色warning
同理,FlatList如果有很多图片要渲染,上下拉刷新时也会出现这些情况

23、安卓打包错误

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:validateSigningRelease'.
> Keystore file /Users/macbookpro-luoguangcong/projects/newapp/android/app/my-release-key.keystore not found for signing config 'release'.

android/app文件夹下面缺一个my-release-key.keystore文件,去旧项目复制过来即可

24、打包realease包的时候报错 main.jsbundle does not exist. This must be a bug with + echo 'React Native

先打包debug版本 看看有没有JS代码错误
如果确认OK,再重新yarn一次

25、webview 监听页面变化(不是自己写的H5,没办法使用postMessage)

96fe8710-9d55-42d2-b8e5-d4b8306e4fcb

_onNavigationStateChange(webViewState) {
    // console.log('webview ???', webViewState);
    if (webViewState.url.indexOf('*****') >= 0) {
      this.props.repaymentActions.repaymentSetCreditCardListNew();
      this.props.navigator.pop();
    }
  }

26、传参问题 企图修改原型属性

One of the sources for assign has an enumerable key on the prototype chain. Are you trying to assign a prototype property? We don't allow it, as this is an edge case that we do not support. This error is a performance optimization and not spec compliant.

451d9db7-847d-414f-9242-bb21cf12fab3

该传的参数还是得传
bc76b168-f431-435e-bb51-9e589072df17

27、关闭弹窗后自动执行两次路由操作

点击弹出框Btn => 收起弹框 => 切换tab => push进其他页面
1、收起弹框、切换tab,easy
2、当前处于什么scene就切换什么scene
3、在切换后的“我的“页面通过componentWillReceiveProps监听scene的变化,然后push到对应的组件去

d1e051b0-3de0-485e-b10c-a112b8874f69

28、App与webview(H5)通信

postMessage发送消息

sendMessage(data) {
    this.webview.postMessage(data);
  }

onMessage监听

<WebView
  injectedJavaScript={ debug}
  style={}
  source={{ uri: *** }}
  userAgent={'GuardianAppIOS/1.0.0 Webview'}
  onMessage={this.handleMessage}
/>

但这里有个bug
react native html postMessage can not reach to WebView · Issue #11594 · facebook/react-native · GitHub

// the react native postMessage has only 1 parameter while the default one has 2, so check the signature of the function
  waitForBridge(option) {
    if (window.postMessage.length !== 1) {
      setTimeout(() => {
        this.waitForBridge();
      }, 200);
    } else {
      window.postMessage(
        JSON.stringify(option)
      );
    }
  }

通过观察者(发布-订阅)模式进行页面的跳转
先实例化一个事件发布器

import EventEmitter from 'react-native/Libraries/vendor/emitter/EventEmitter'

let emitter = new EventEmitter()

export default emitter
if (url.startsWith('http://') || url.startsWith('https://')) {
    return emitter.emit('NAVIGATION_NAVIGATE_TO', 'WebView', url, extraData)
  }

在navigator进行监听,以及销毁时的移除

// add eventlistener: navigate to
    emitter.addListener('NAVIGATION_NAVIGATE_TO', (routeName, url, extraData) => {
      this.props.dispatch(
        NavigationActions.navigate({
          routeName,
          params: routeName === 'WebView' ? { url, ...extraData } : {},
        })
      )
    })
componentWillUnmount() {
    emitter.removeAllListeners()
  }

29、配置schemes URL

React Native URL Scheme and Linking API - Johnson Su
非常棒的指引

30、切换App主题

1、替换整个app(理解为品牌)
将所有color、size、position相关属性抽离出来,放到一个公共文件commonStyles.js,导出常量使用
该文件根据config.js中的THEME进行判断采用哪一套主题
如此,只需要修改THEME即可,达到一键替换的作用

2、app换皮肤
新建一个BaseCommon.js页面,作为这四个页面的父类。在这个父类里面接收主题更改的通知,并更新自己的主题。这样一来,继承它的这四个页面就都会刷新自己

31、中间模态窗

大概思路:
1、第三个导航样式上采用区别对待,该tab本来在路由系统中对应了一个页面组件,现在设置为null,改写它的点击事件(其他四个按钮则是正常的切换tab事件),点击则出现全屏弹层
f93afb37-0fba-48fe-ad99-4e7e5ed5aa6a

2、为实现弹层效果,给一个动画效果,并占满全屏
02145d25-a1e6-4e70-b22b-07c65acaa263

wrapper: {
    position: 'absolute',
    top: 0,
    left: 0,
    bottom: 0,
    right: 0,
    backgroundColor: templateUsage.shouldUseTemplateDaily()
      ? '#191A22'
      : 'rgba(40, 47, 51, 0.8)',
  },

3、弹层上的路由设置
直接抛弃掉真正的路由系统,用状态来控制页面的隐藏和显示,假装是push进一个页面,其实只是由一个state状态来控制一个页面显示,一个页面隐藏而已

消失或者隐藏,也就是加个动画,然页面更自然

closePopularize() {
    this.state.y.setValue(0);
    Animated.timing(this.state.y, {
      toValue: Dimensions.get('window').height,
      duration: 200
    }).start(this.props.popPopularize);
  }

  clearPopularize() {
    this.state.y.setValue(0);
    Animated.timing(this.state.y, {
      toValue: Dimensions.get('window').height,
      duration: 200
    }).start(this.props.clearPopularize);
  }

总结的很好,另外还有个坑,ios9.0和10版本SafeAreaView组件不支持,需要手动判断

@shx1545 噢 对,这个忘了写了 感谢大佬

@amandakelake react-native自带的SafeAreaView组件是不支持ios10及以下,如果要用了react-navigation,可以引入它里面的。
import {SafeAreaView} from 'react-navigation'

@shx1545 嗯嗯 对的

请问一下25有没有什么好的方案可以解决

@yezidd 不是已经写出来了么 监听页面url的变化

webview 里面 alert 没有反应 , 这个可以解决吗?

第21,生命周期中的componentWillReceiveProps 将要弃用了,使用�新的 getDerivedStateFromProps

您好,请问下,一个App唤醒另一个App并且传参 ,react-native 能做到吗??

@jim888666 你搜索一下Linking看看

mrzxc commented

22条在FlatList中的image未卸载bug 应该是已经修复了

安卓的字体偏大,在屏幕上总是会出现文字被挡住一点,这个该怎么搞

com.facebook.jni.CppException: Could not get BatchedBridge, make sure your bundle is packaged correctly

这个是什么原因?大佬

com.facebook.jni.CppException: Could not get BatchedBridge, make sure your bundle is packaged correctly

这个是什么原因?大佬