ReactNative新手踩过的一些坑

最近在学习React Native,学习实现过程中遇到的一些问题和心得,先总结一部分出来,与大家一起学习进步。
大部分简单的功能实现官方文档的说明都很清楚,我这里主要说一下我在开发过程中遇到的一些棘手的问题和解决办法

1.布局和视觉样式部分

a.RN中如何实现FrameLayout效果

如果要在RN中实现类似Android中的FrameLayout效果,需要对view的style设置 positon: 'absolute' ,以及一些方向属性

goods_left_label_style: {
    position: 'absolute',//相对父元素进行绝对定位
    left: 0,
    top: 0,
    right:0,
    bottom:0 //后面四个根据需要设置
},
b.等比例权重布局

要进行等比例权重布局需要使用一个重要的属性,flexDirection,该属性用于指定主轴的方向。即指定子view的布局方向。可以设置两个值分别是:row和column。感觉上类似于orientation。接着在子布局中设置flex属性就是view的权重了,类似于android中的weight。

除了flexDirection之外还有几个很重要的属性,下面说明一下他们的使用方法:

justifyContentalignItems,这两个属性是相对的,第一个是设置子View的水平方向布局,第二个是设置VIew的竖直方向布局,他们的取值有相同也有不同。这两个属性都可以取三个值,分别是flex-start,flex-end,center,意思分别是顶部对齐,底部对齐,居中对齐。

接着说他们不同的部分,justifyContent还有一个stretch属性,意思是在竖直方向上填充整个父布局;alignItems有两个分别是space-between和spage-around属性,这两个很特别在android上是没有的,space-between意思是第一个子组件位于父容器左端,最后一个子组件位于父容器最右端。然后平均分配在父容器水平方向上。space-around指所有子组件平均分配在父容器的水平方向上,左右都有留空隙。

以上的两个属性都是父布局管理子布局的属性,还有一个属性是alignSelf,他是用来单独设置组件竖直方向的样式,与alignItem类似,只是一个设置父一个设置子。

flexWrap用于设置子view是否可以换行,有两个属性可设置nowrap和wrap。nowrap:即使空间不够也不换行。wrap:空间不够的话自动换行。

c.View中设置Style

多个style可以组合起来使用。比如:

<Text style={[styles.bigblue, styles.red]}>red, then bigblue</Text>
const styles = StyleSheet.create({
  bigblue: {
    color: 'blue',
    fontWeight: 'bold',
    fontSize: 30,
  },
  red: {
    color: 'red',
  },
});

因为后写的red所以,里面的color会覆盖掉之前bigblue的color,但是其他的属性仍然沿用bigblue中的。

d.点击事件

在RN中的点击事件似乎必须在需要点击的View外部嵌套一个"Touchable"开头的一系列组件,这些组件通过onPress属性接受一个点击事件的处理函数,在函数中处理相应的点击事件。看一下代码:

<TouchableOpacity onPress = {this._onPressBack}>
    <Image style = {styles.title_btn_style} source = {THUMB_URLS[0]} resizeMode = "contain"/>
</TouchableOpacity>

_onPressBack(){
    AppModule.finishActivity()
}
e.显示或隐藏view

RN感觉并没有像Android那样提供visible这样的属性,可以直接通过设置visible来控制view的显示。如果要控制view的显示的话,需要在render view的时候设置相应的显示隐藏方法。再通过state状态值的改变来在交互过程中进行更新。看下代码:

render() {
    return (
        <View style = {{flex:1}}>
            <View style = {styles.occupy} />
            {this._getPersonalActivityRemindView()}
            {this._getPullToRefreshListView()}
        </View>
    );
}

_getPersonalActivityRemindView() {
    if (this.state.personalActivityRemind !== '') {
        return (
            <View>
                <View style = {{padding: 10,alignItems: 'center',backgroundColor: '#FFFFFF'}}>
                    <Text style = {{color: '#333333'}}>
                    </Text>
                    <Text style = {{color: '#e31436'}}>
                        {this.state.personalActivityRemind}
                    </Text>
                </View>
                <View style = {styles.occupy} />
            </View>
        )
    }
}

2.针对新手关于ES5和ES6的问题

网上关于RN的文章越来越多了,但是随着ES6的普及,网上大部分的代码都是有的用ES5有的用ES6,还有两个混着用的。我在一开始不是很熟悉看得时候很容易错乱,推荐在看官方文档的时候可以顺便看一眼这篇文章,我涉及到的大部分ES的问题这里都说到了。
react-native-的es5-es6写法对照表,而且从0.18开始,RN的新项目默认模板已经全面转向ES6了。

3.使用ref可以在外部使用view的引用

使用ref可以在某些view不方便通过props或state更新的时候使用,主要是在render外面使用view的引用。

render: function() {
    return <TextInput ref={(c) => this._input = c} />;
  },
  componentDidMount: function() {
    this._input.focus();
  },

上面的代码通过制定引用,在外部的componentDidMount方法中便可食用此view的引用。ref同样可以使用字符串,例如:ref = "listview",这种方式在外部使用的时候需要这样调用:this.refs.listview。剩余细节的使用方法可以参考文章:Refs to Components

4.ListView使用遇到的一些问题

a.RN在0.24.1版本之后ListView在使用过程中会出现empty section headers 的警告。

Warning: In next release empty section headers will be rendered. In this release you can use 'enableEmptySections' flag to render empty section headers.

如果需要去除这个警告的话需要在listview中添加enableEmptySections = {true}

b.RN官方的ListView中本身提供了上拉分页刷新,在ListView组件中使用onEndReach()方法可以很简单的实现上拉分页加载效果。同时,针对下拉刷新,RN官方的ListView也提供了RefreshControl来管理,可以在ListView中直接使用RefreshControl来实现下拉刷新效果。

<ListView
    refreshControl={
      <RefreshControl
        refreshing={this.state.refreshing}
        onRefresh={this._onRefresh.bind(this)}//刷新方法需要自己实现
        onEndReached = {this._onEndReached}//滚动到底是加载数据的方法需自己实现
        onEndReachedThreshold = {40}//这个参数表示距离底部多少时出发onEndReached
      />
    }
    ...

5.自定义view

先总结一下在原有组件之上定义自己的view。目前还不会完全自定义view的实现。

1.自定义自己需要的属性,类似于Android中的attrs,首先需要声明属于自己的PropTypes以及他们的类型,例如:

propTypes: {
    customStyles: React.PropTypes.object,
    initialListSize: React.PropTypes.number,
    firstLoader: React.PropTypes.bool,
    paginationFetchingView: React.PropTypes.func,
    onFetch: React.PropTypes.func,
}

这样声明相当于设置一个验证器,当向 props 传入无效数据时,JavaScript 控制台会抛出警告。

2.通过getDefaultProps方法可以给自定义的属性设置默认值

getDefaultProps() {
return {
  customStyles: {},
  initialListSize: 10,
  firstLoader: true,
  pagination: true,
      onFetch(page, callback, options) { callback([]); },
}

3.当某个属性没有被重新定义的时候,作为自定义的view,最好可以定义一个通用的方法,即默认流程,来防止出现一些问题

renderSeparator() {
    if (this.props.renderSeparator) {
          return this.props.renderSeparator();
    }
    return (
      <View style={[this.defaultStyles.separator, this.props.customStyles.separator]} />
    );
},

4.通过getInitialState方法设置初始换的状态值,通过状态值的改变可以更新view的显示效果,例如更新listview的数据,让listview加载更多等。

getInitialState() {
  this._setPage(1);
  this._setRows([]);
  return {
    dataSource: ds.cloneWithRows(this._getRows()),
    isRefreshing: false,
    paginationStatus: 'firstLoad',
  };
},

5.setNativeProps方法

如果你通过React.createClass方法自定义了一个组件,直接给它设置样式prop是不会生效的,你得把样式props层层向下传递给子组件,直到子组件是一个能够直接定义样式的原生组件。同理,我们也需要把setNativeProps传递给由原生组件封装的子组件。

  setNativeProps(props) {
    this.refs.listview.setNativeProps(props);
  },

  render() {
    return (
      <ListView
        ref="listview"
        dataSource={this.state.dataSource}
        renderRow={this.props.rowView}
        {...this.props}
        style={this.props.style}
      />
    );
  },

其中View中设置的{...this.props}这句话也很重要,我的理解是所继承的原生view属性太多,通过这句话复用父类的方法。比如你不想自己处理点击拖动效果,就直接继承过来.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容