react-native 踩坑記

最近在使用react-native的時候遇到了不少坑,這裏給你們分享下javascript

一.樣式

react-native 雖然支持flex佈局,可是全部的樣式均是css樣式的一個很小的集合,尤爲是在安卓機下問題尤其凸顯:css

1.View內部的元素千萬不要超出父級的範圍,iso上問題卻是不大,安卓上就什麼超出的都看不到了java

2.lineHeight 能夠用,不過千萬不要寫成小數,不然安卓上會直接崩潰node

3.rn的樣式不存在繼承的狀況,因此基本上每一個節點都要寫style,真的是體力活react

4.若是Text的父級元素設置了背景顏色,那麼ios下Text的背景顏色也是父級的背景顏色,要麼本身寫個Text重置下樣式,要麼就遇到了再改android

5.react-native的字號是沒有設置單位的,因此會隨着系統設置的字體大小而變化,我也不知道這是否是坑,不過貌似有的app也沒有管這個,若是硬要去設置Text的文字不隨系統改變,安卓是能夠統一設置的,ios上Text設置allowFontScaling ={false}就能夠解決ios

二.異常

react-native 在發生js異常的時候,debug的時候會直接紅屏幕,可是再release的時候直接會崩潰退出,解決辦法git

import ErrorUtils from "ErrorUtils" 
//這裏應該作個判斷,若是不是debug的才作這樣的異常全局處理 ErrorUtils.setGlobalHandler((e)=>{
  //發生異常的處理方法,固然若是是打包好的話可能你找都找不到是哪段代碼出問題了   Alert.alert("異常",JSON.stringify(e)) });

三.fetch

react-native雖然自帶有fetch,不過在使用的時候發現了一個問題,若是須要獲取http的header頭的時候問題就來了,可能獲得的是一些千奇百怪的樣式,這並非react-native的錯,而是第三方的 whatwg-fetch 留下的坑,固然也有人再github上跟react-native反映過這個問題,不過獲得的解決方案都很坑,惟有一個辦法,就是拷貝本身修改,修改以下:github

1.註釋該註釋的ajax

(function(self) {
    'use strict';
   //註釋這裏,否則老是用的是全局的fetch
    // if (self.fetch) {
    //     return
    // }

2.修改該修改的

function parseHeaders(rawHeaders) {
        var headers = new Headers()
     //把\t\n改爲\t,由於通常header都是用\n來分割的 rawHeaders.split('\n').forEach(function(line) { //rawHeaders.split('\t\n').forEach(function(line) { var parts = line.split(':') var key = parts.shift().trim() if (key) { var value = parts.join(':').trim() headers.append(key, value) } }) } return headers }

3.直接import你改好的文件,fetch就能夠用了

四.Modal

Mode控件在使用的時候要注意了,由於這個是rn提供的,而且也寫的很清楚是最高層級的一個彈出層,因此你想要又打開Model又要跳轉基本是無望的了,因此建議不要使用這個,最好是使用第三方的控件,咱們用的是 react-native-modalbox + 高階控件 實現的全遮蓋的彈出層

五.點擊屏幕其餘位置關閉的菜單

這類菜單有個共同的特色就是點擊屏幕其餘地方而後菜單就關閉,咱們的解決辦法就是用本身寫的 react-native-modalbox + 高階控件 也就是說放在一個彈出層裏面,固然能夠試試把當前頁面套進一個大的 TouchableWithoutFeedback 裏面

六.接口請求

非特殊狀況下都應該這樣作

import {InteractionManager} from "react-native"

componentDidMount(){
  InteractionManager.runAfterInteractions(() => {
      fetch("xxx.xxx.xxx",{})
    });      
}

七.鍵盤

官方提供的自定義隱藏鍵盤的方法是

import { Keyboard } from 'react-native'

Keyboard.dismiss()

可是我試了不少次以後發現根本不能,並且還報錯,樓主的react-native版本是0.35.0

看了官方的issue才知道這個不行,推薦下面方法

import dismissKeyboard from 'dismissKeyboard'
dismissKeyboard()

這樣就能夠隱藏了,太坑了  

 

還有個很坑的地方,官方提供的移除鍵盤事件的方法不可用

componentDidMount () {
  Keyboard.addListener('keyboardDidShow', this.keyboardDidShow.bind(this))
  Keyboard.addListener('keyboardDidHide', this.keyboardDidHide.bind(this))
}

componentWillUnmount () { Keyboard.removeAllListeners('keyboardDidShow') Keyboard.removeAllListeners('keyboardDidHide') }

這樣的方式特麼的若是操做快了,或者有時候莫名其妙的就會出錯,下面的纔是正確的打開方式:

componentDidMount () {
  this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this.keyboardDidShow.bind(this))
  this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this.keyboardDidHide.bind(this))
}
componentWillUnmount () {
    this.keyboardDidShowListener.remove()
    this.keyboardDidHideListener.remove()
}

八.https

https這個問題上ios還好,安卓問題就來了,前期咱們準備將ajax請求的庫丟給原生安卓和ios來作咱們直接調用就是了,可是後來發現問題這樣那樣的問題太多了,

因此在熱更新服務器啓動或者打包的時候就把源代碼先改了在進行打包或者啓動服務器

文件位置:

node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/OkHttpClientProvider.java

這個文件的最後一個方法修改以下:

  private static OkHttpClient createClient() {
    // No timeouts by default
    return new OkHttpClient.Builder()
    .sslSocketFactory(sslContext.getSocketFactory())
    .hostnameVerifier(new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
                return true; //忽略全部的認證,直接返回了true
            }
          })
      .connectTimeout(0, TimeUnit.MILLISECONDS)
      .readTimeout(0, TimeUnit.MILLISECONDS)
      .writeTimeout(0, TimeUnit.MILLISECONDS)
      .cookieJar(new ReactCookieJarContainer())
      .build();
  }

修改源代碼的方式有點略坑,不過能夠解決不少問題,還節約時間!!!

九.BackAndroid

安卓機有獨特的點擊按鍵返回,因此在最外層會註冊一個監聽方法

    bindHardwareBackPress(){
        if (Platform.OS === 'android') {
            BackAndroid.addEventListener('hardwareBackPress', this._onHomeBackPress);
        }
    }

    onHomeBackPress(){
        let routeList = this.getRouteList();
        if (routeList.length !== 1) {
            this.navigator.pop();
            return true;
        }

        this.handleHomeBackPress();
        return true;
    }

    handleHomeBackPress(){
        if (Platform.OS === "android") {
            ToastAndroid.show("再按一次退出應用", ToastAndroid.SHORT);
            BackAndroid.removeEventListener("hardwareBackPress", this._onHomeBackPress);
            BackAndroid.addEventListener("hardwareBackPress", this._onExitApp);
            this.timer = TimerMixin.setInterval(() => {
                TimerMixin.clearInterval(this.timer);
                BackAndroid.removeEventListener("hardwareBackPress", this._onExitApp);
                BackAndroid.addEventListener("hardwareBackPress", this._onHomeBackPress);
            }, 2000);
        }
    }

    exitApp(){
        BackAndroid.exitApp();
    }

上面的代碼是監聽返回鍵,若是不是在最外層的路由就返回上一個,若是在最外層就直接關閉app,可是有不少這樣那樣的需求要去對安卓的返回鍵進行操做,坑就來了,你覺得提供的removeEventListener方法是沒問題的?no !!! 他會移除全部的監聽,這是否是很坑!!!!

因此:在須要對安卓返回鍵進行特殊處理的時候記得其餘地方作了監聽的再從新監聽一次!!!!

相關文章
相關標籤/搜索