ReactNative组件详解

ReactNative学习记录传送门

ReactNative核心思想就是组件化,它基于前端框架React,在我们使用其开发Android和iOS的时候,共用一套组件即一套代码,增加了代码复用性。今天的这篇文章不不分析过多的知识点,主要介绍如下内容:

  • 如何进行自定义组件
  • 如何使用自定义组件
  • 组件的生命周期

自定义组件

ReactNative中我们实现的UI都是有组件组成的,但是有时候为了实现我们想要的效果,并且达到重用代码的目的,往往需要我们自定义组件,那么此时我们就需要对自定义组件的套路有一些见解。需要注意的是本篇文章是基于ES6的,但是若写法与es5有差别的地方也会顺带提一下。

由于自定义组件是也是由基本的组件经过一些业务的处理组装而成,那我们我们首先要了解ReactNative中基本的组件都有哪些,可前去官网查看.今天我们要实现的组件就是一个购物车数量加减功能。全文也围绕这个小栗子展开介绍,效果如下

image.png

要实现这样的一个组件,我们首先要知道Component,当我们创建组件的时候必须要继承Component(ES5是使用React.createClass创建组件),而上图的组件我们使用最基础的组件Text来实现,就是三个Text在View里横向放置。在ReactNative开发时,如果我们使用基本组件或者其自定义的组件时,首先要做的工作就是导入,在ES6中使用关键字import来实现这一功能。导入基本组件Text,View以及组件类Component,当然为了读写代码方便,我们将样式统一管理,则需要用到StyleSheet来创建样式。则导入部分

import React, {Component} from 'react';
import {
    Text,
    View,
    StyleSheet
} from 'react-native';

上面是ES6s实现导入的,在最近几天的学习中发现很多代码依然是ES5的方式,那么我们对ES5也要有简单了解,ES5方式

var React = require('react');
var ReactNative = require('react-native');
var {
    Text,
    View,
    StyleSheet
} = ReactNative;

导入之后我们就可以开始使用了,创建组件我们最重要的就是继承Component,重写render方法,render方法返回的就是一个组件的集合,它决定了最终显示的界面效果。

class CustomComponent extends Component {
    render() {
        return <View style={styles.container}>
            <Text
                style={styles.reduce}
            >-</Text>
            <Text
                style={styles.text}
            >5</Text>
            <Text
                style={styles.add}
            >+</Text>
        </View>
    }
}

要达到我们想要的效果,样式是必不可少的,对于样式我们可以直接在组件中实现,如 style={{ flexDirection: 'row'}},它和CSS样式几乎是通用的含义,不同的是在ReactNative中采用了驼峰命名方式。例如css中flex-direction在RN中就是把下划线去掉,然后后面字母大写。这样写了之后我们会发现,样式重用性就小了,最重要的是样式和组件都糅合在一起,看起来也不美观,facebook也不推荐我们这样做,他推荐的是使用StyleSheet统一管理.上面的样式实现

const styles = StyleSheet.create({
    container: {
        flexDirection: 'row',
        marginBottom: 20,
        marginTop: 20,
    },
    reduce: {
        width: 50,
        height: 40,
        borderWidth: 1,
        textAlign: 'center',
        textAlignVertical: 'center',
        borderColor: '#ccc',
        borderBottomLeftRadius: 5,
        borderTopLeftRadius: 5
    },
    text: {
        width: 50,
        height: 40,
        borderTopWidth: 1,
        borderBottomWidth: 1,
        textAlign: 'center',
        textAlignVertical: 'center',
        borderColor: '#ccc',
    },
    add: {
        width: 50,
        height: 40,
        borderWidth: 1,
        textAlign: 'center',
        textAlignVertical: 'center',
        borderColor: '#ccc',
        borderBottomRightRadius: 5,
        borderTopRightRadius: 5,
    }
})

在RN中,组件的默认是纵向排列的,所以我们在View组件样式中通过flexDirection设置水平(row)排列。然后就是设置边框宽度,边框颜色及边框的圆角半径,通过textAlign设置文字水平居中,通过textAlignVertical设置文字垂直居中。

组件的使用

使用就很简单了,和我们使用基本组件套路是一样的,在使用之前,我们要将定义的组件CustomComponent 暴露出来,共外部使用,在ES6中,导出组件如下

export default class CustomComponent extends Component {}

ES6使用module.exports=CustomComponent 导出,使用就很简单了,如下

<CustomComponent />

状态和属性

上面实现过后,我们就能看到文字开头图片实现的效果了,但是我们还没有实现事件监听功能,即当点击左侧减号中间的数字减1,直到0,当点击加号时,中间文本要加1。要实现这种功能就需要了解state(状态)了。当state发生改变的时候,组件会重新执行render函数刷新界面的数据。
一般的我们会在constructor方法中初始化state.(如果使用es5通过getInitialState函数初始化,es6中无此方法),例如我们在组件初始化时将数量设置为0

 constructor(props) {
        super(props)
        //ES6写法,ES5 getInitialState
        this.state = {
            count: 0,
        }
    }

然后我们分别给减号和加号的Text添加点击(onPress)监听,并更改state中count的值,使其重新执行render刷新界面数据。render部分代码更改如下

 render() {
        return <View style={styles.container}>
            <Text
                style={styles.reduce}
                onPress={this.reduce}
            >-</Text>
            <Text
                style={styles.text}
            >{this.state.count}</Text>
            <Text
                style={styles.add}
                onPress={this.add}
            >+</Text>
        </View>
    }

当点击时,首先通过this.state.count获取当前的值,如果点击减号就将该值减1,点击加号就将该值加1,最终要的是需要通过this.setState()将state更新改变后的值。当state发生改变时,render函数执行,则此时我们看到的数据已经是更改过后的值。

点击事件

reduce = () => {
        this.setState({
            count: this.state.count > 1 ? this.state.count - 1 : 0
        })
    }
add = () => {
        this.setState({
            count: this.state.count + 1
        })
    }

通过我们分别给加号和减号增加点击事件onPress,实现了数量加减的功能。

可能很多时候我们要碰到这个问题,例如,当我们从一个商品列表进入商品详情时往往会有了一个购买数量,通俗的说,我们需要给我定义组件传递一个值,这个值就是我们之前已经选择的商品数量。那么要实现这样的效果就需要用到属性了。
在前面介绍状态的时候,我们重写构造函数constructor,他有一个参数props,这就是属性,在使用组件时所传入的属性都可以通过this.props.属性名 获得。此时我们对构造函数做一下修改,如下

    constructor(props) {
        super(props)
        //ES6写法,ES5 getInitialState
        this.state = {
            count: this.props.count,
        }
    }

count的初始值不在是0,而是为我们定义的值,问题又来了,如果使用组件的时候设置属性count,那么这样取值不是有问题吗,那如何解决呢。这就用到defaultProps,我们可以使用它定义默认的属性值,即如果有传值的时候就用传的值,如果没有传值就用默认值。我们定义默认值为1

    static  defaultProps = {
        count: 1
    }

这样发现组件使用起来很不错的感觉,可是有一天,有人使用组件时传了一个不是数字的值....字符串。你可能会说,这是使用者的问题,but...我们还是要解决的,在RN中提供了属性类型检查功能,约束我们传入的值。

    static propTypes={
        count:PropTypes.number,
    }

通过上面后,就做了一个类型检查,限制数字类型,再类型检查时我们还可以使用isRequired限制该属性是否必填。属性功能很强大,不仅能传值,还有以传函数。再次就不多介绍。
在使用时给组件加入属性count

<CustomComponent 
    count=3
  />

生命周期

每个组件都有生命周期方法,我们可以重写这些生命周期方法在运行时特定的世时间执行。
总体来说生命周期分为三类

Mounting

该状态表示某个组件被创建的,也就是初始化组件。

  • constructor(props)
    当然构造方法constructor是必不可少的,它是被装载之前调用,也是最先调用的函数,当我们重写constructor时候,必须加参数props,并s首先调用super(props),否则在构造方法中使用props都是undefined,显然这回导致c出现严重的bug.,在这里我们一般要做的是根据属性对状态进行初始化。
  • componentWillMount()
    在组件开始渲染之前调用,也就是再render方法之前,在这个阶段并没有对组件进行渲染
  • render()
    该方法在组件中是必须的,一旦调用,则去检查 this.props 和 this.state 的数据并返回一个 React 元素。render() 方法不能修改组件的 state,同时需要注意的是,shouldComponentUpdate() 方法必须返回 true,否则当状态或者属性值发生改变时将不会再执行 render() 方法。
  • componentDidMount()
    当组件被渲染之后,会被调用,用来通知组件已经加载完成,通常我们会在这里去从服务器拉取数据来渲染页面。在这个方法中设置状态组件将会被重新渲染。

Updating

  • componentWillReceiveProps(nextProps)
    当组件接收到一个新的属性时,将会被调用,如果我们需要根据属性对状态进行更改,(可以通过this.props和nextProps对比)可以在此设置state,在该函数参数nextProps即为更改后的属性。
  • shouldComponentUpdate(nextProps, nextState)
    当组件接收到组件 state 或者props发生改变时 ,该方法键会被调用,参数nextProps为设置的属性,nextState为设置的状态。一般我们会根据this.props和nextProps或者this.state和nextState对比,值是否发生变化来返回true或者false.如果返回true就会重新渲染界面,否则的话就不会继续执行渲染逻辑
  • componentWillUpdate(nextProps, nextState)
    该函数在接收到属性或者状态时调用,并且在render之前,shouldComponentUpdate之后调用,shouldComponentUpdate如果返回false的话,该方法就不会调用了。
  • render()
    与Mounting状态下的render作用一样。
  • componentDidUpdate(prevProps, prevState)
    表示调用 render() 方法完成了界面的更新,需要注意的是,该方法在初始的 render 后将不会被调用,只有设置属性或者状态时才会调用。参数是更改之前的属性和状态,此时通过this.state或者this.props已经是更改后的值。

Unmounting

  • componentWillUnmount ()
    在组件被销毁或者退出的时候调用,在该方法中我们可以执行任何必要的清理工作,比如失效计时器,取消网络请求等

生命周期回调顺序

在前文我们实现数量加减的组件的基础上,我们重写所拥有生命周期并在生命周期中加入console打印函数名来观察执行顺序。

初始化组件:

constructor
componentWillMount
render
componentDidMount

设置状态时

shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate

设置属性时

componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate

卸载组件

componentWillUnmount

到这里,今天这篇文章要介绍的内容也就介绍完毕了,当然还有很多知识点是没有提到的,可以去参考ReactNative的官方网站。由于我也是水平有限,难免会有想不到或者说理解不到位的地方,若在阅读文章的时候发现错误的地方,欢迎指正,我及时更改,以免误导大家。

如果你对学习RN有兴趣,可以访问我的学习记录的项目,GitHub地址

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

推荐阅读更多精彩内容