RN 最容易crash的代碼用法及應對措施(持續更新)

變量保護

出現最多的就是在使用redux來做數據層,使用this.props的屬性沒有去查詢時候爲undefined,這種情況,基本是必crash

比如下例:

//show user name
<Text>{this.props.userInfo.name}</Text>

如果userInfo爲undefined的話,就會崩潰,錯誤如下:

TypeError: Cannot read property ‘name’ of undefined

在這裏name爲undefined的時候反而沒有問題,因爲name是一個簡單的屬性,直接賦值給Text是沒有問題的。

那如何避免這種問題呢?在賦值前加下判斷會比較好:

let name = this.props.userInfo && this.props.userInfo.name ? this.props.userInfo.name : '';

//show user name
<Text>{this.props.userInfo.name}</Text>

這樣基本可以避免崩潰的問題了。

但是如果都這樣判斷,實際是比較複雜的,所以如果你的業務比較簡單,我建議可以直接在render做一個大的保護,即沒有數據的時候,不去render這些業務內容.
思路如下:

render(){
    if(!this.props.userInfo){
        return (
            <EmptyView />
        )
    } else {
        return (
            //注意,如果name的層級更深,還是建議做保護
            <Text>{this.props.userInfo.name}</Text>
        )
    }
}

定時器

定時器其實在iOS中也是一個非常容易出問題的地方,crash率會比較高。究其原因,我想是主要是因爲定時器存在一個事件發生的延後性(廢話嘛0_o),但是很多時候會忘記,當定時任務真的發生的時候,語境變化了嗎?如果語境都已經被dealloc了,定時任務仍然被激活,系統就會憤怒地罷工了。

比如:

componentDidMount() {
    setTimeout(
      () => { console.log('這就可能會崩潰'); },
      500
    );
  }

如果500ms之內,這個component就會Unmount了,那直接回崩潰。RN官方的建議如下:

TimerMixin

爲了解決這個問題,我們引入了TimerMixin。如果你在組件中引入TimerMixin,就可以把你原本的setTimeout(fn, 500)改爲this.setTimeout(fn, 500)(只需要在前面加上this.),然後當你的組件卸載時,所有的計時器事件也會被正確的清除。

這個庫並沒有跟着React Native一起發佈。你需要在項目文件夾下輸入npm i react-timer-mixin –save來單獨安裝它。

var TimerMixin = require('react-timer-mixin');

var Component = React.createClass({
  mixins: [TimerMixin],
  componentDidMount: function() {
    this.setTimeout(
      () => { console.log('這樣我就不會導致內存泄露!'); },
      500
    );
  }
});

代碼保護(推薦)

Mixin屬於ES5語法,對於ES6代碼來說,無法直接使用Mixin。如果你的項目是用ES6代碼編寫,同時又使用了計時器,那麼你只需銘記在unmount組件時清除(clearTimeout/clearInterval)所有用到的定時器,那麼也可以實現和TimerMixin同樣的效果。例如:

import React,{
  Component
} from 'react';

export default class Hello extends Component {
  componentDidMount() {
    this.timer = setTimeout(
      () => { console.log('把一個定時器的引用掛在this上'); },
      500
    );
  }
  componentWillUnmount() {
    // 如果存在this.timer,則使用clearTimeout清空。
    // 如果你使用多個timer,那麼用多個變量,或者用個數組來保存引用,然後逐個clear
    this.timer && clearTimeout(this.timer);
  }
};

我今天看了我們項目的代碼,發現幾乎沒有人做保護,代碼copy的現象,真的是令人髮指,可能很多人都沒仔細看過官方的文檔。。。

RN0.43 Text組件bug

最近公司升級了RN的版本,從0.39升級到了0.43,這裏出現了一個比較嚴重的bug。github上的issue地址:[https://github.com/facebook/react-native/issues/13080
](https://github.com/facebook/react-native/issues/13080
)

具體來說,就是android上面的Text,string和int等數值混排會出現莫名的bug,無論Text是否加了點擊事件,只要觸摸int等數值的展示部分,就會崩潰,具體代碼如下:

let num = 5;
<Text>有{num}個贊</Text> //點擊crash

如何補救呢?使用.toString:

let num = 5;
<Text> 有{num.toString()}個贊</Text> //ok

看github上的記錄,0.44已經修復,但是如果使用0.43的同學,千萬要小心。

更新於 2017-05-10

字符串作爲判斷條件 崩潰bug

類似這樣:

let test = {string: ''};
return (
    <View>
        {test && test.string &&
        <Text>{test.string}</Text>
        }
    </View>
)

報錯:

Error: RawText "" must be wrapped in an explicit <Text> component.  

原因未知,但是會崩潰

保護措施:

let test = {string: ''};
return (
    <View>
        {test && !!test.string &&
        <Text>{test.string}</Text>
        }
    </View>
)

具體的可以看下這篇文章:Error RawText ** must be wrapped in an explicit component 問題解決

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章