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地址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值