美文网首页
React Native 入门介绍

React Native 入门介绍

作者: 安静守护你 | 来源:发表于2018-11-14 12:21 被阅读3896次

    前言

    上篇文章讲了自己在搭建React Native环境时遇到的问题,这篇就接着来说一下RN项目的基础,包括布局、各种事件等项目日常开发需要用到的,同时也是做一个记录,方便以后自己查询。

    正文

    环境搭建好了,接下来就是最基本的Hello World咯,不过不着急,可以先使用Xcode打开HelloWorld项目来看一下项目概况。

    项目结构

    以上就是项目的基本结构,其中包括了我们最常见的AppDelegateImages.xcassetsInfo.plistLaunchScreen.xibmain.m、这几个文件外,还出现了一个Libraries文件夹,其中有很多以.xcodeproj结尾的文件,这些应该是引入的库文件,可以暂时先放放,先我们最为熟悉的main.mAppDelegate文件。

    main.m

    main.m文件中,还是跟我们原生的iOS新建项目中的main.m一样,作为程序的起始点,将程序的入口引向了AppDelegate文件。

    再来看看AppDelegate文件,.h文件中没有什么变化,但是在.m中却有些改变,以下是.m文件中的代码

    #import "AppDelegate.h"
    
    #import <React/RCTBundleURLProvider.h>
    #import <React/RCTRootView.h>
    
    @implementation AppDelegate
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
      NSURL *jsCodeLocation;
    
      jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
    
      RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                          moduleName:@"HelloWorld"
                                                   initialProperties:nil
                                                       launchOptions:launchOptions];
      rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
    
      self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
      UIViewController *rootViewController = [UIViewController new];
      rootViewController.view = rootView;
      self.window.rootViewController = rootViewController;
      [self.window makeKeyAndVisible];
      return YES;
    }
    
    @end
    

    在原生的项目中,我们一般都是设置Navwindow.rootViewController,但是这里却将Nav替换成了RCTRootView,虽然不知道是什么,但是根据上面引入的头文件可知,是从React中引入的,我们可以点击进去看一下RCTRootView类的真面目。

    根据进去RCTRootView类中看到的可知其是一个继承自UIView的类,其中包含了两个初始化方法和若干属性,RCTRootView类也充当了该项目的程序主页面咯。

    废话到此为止,接下来就详细介绍一下入门基础。

    Hello World

    学习编程的第一步就是输出Hello World
    使用自己喜欢的编辑器,打开项目根目录中的App.js文件,很简单的几十行代码,看看和运行起来的界面有何联系,更改其中的某一些代码使模拟器中显示出来Hello World这两个英文单词吧,相信大家都会的。这里不再赘述。

    下面给出原始的App.js文件中的代码做出部分讲解(此讲解是以个人第一次见到的第一印象来解释,并不准确,可作为参考,也可培养自己的码感),具体解释直接放在代码旁边

    import React, {Component} from 'react'; // 根据iOS中的#import也可以知道是导入头文件,大概意思就是说从react库中导入React和Component,至于为什么Component用大括号括起来,我也不晓得,或许是类别不一样吧
    import {Platform, StyleSheet, Text, View} from 'react-native'; 
    
    // const 常量声明的关键字,所以可以大概知道后面声明的这是一个常量,常量中又有ios和android两个
    const instructions = Platform.select({
      ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
      android:
        'Double tap R on your keyboard to reload,\n' +
        'Shake or press menu button for dev menu',
    });
    
    type Props = {};
    // 下面这堆东西可以理解为一个名字为App的主类
    export default class App extends Component<Props> {
      render() {
        return (
          // 根据界面显示,可以知道界面上显示的内容就是下面这个View中的内容
          // <View></View>这种写法就跟HTML类似,只不过将<div>换成了view
          // 至于其中跟的style就更明显了,样式声明,可是后面跟的{style.container}是个什么鬼,不过往下面的代码中瞄一眼就立马发现了猫腻,下面声明了一个styles的常量,其中包含了这里所写的styles.container,所以可以知道这里就是将样式声明单独列在一起,避免代码臃肿不便阅读。
          <View style={styles.container}>
            <Text style={styles.welcome}>Welcome to React Native!</Text>
            <Text style={styles.instructions}>To get started, edit App.js</Text>
            // 下面这句代码中的尖括号中写的是{instructions},这里的样式表的值就是用大括号括起来的,这里也是用大括号,所以可以暂时性理解为大括号代表一个变量,大括号中的是变量名字,这里对应的就是上面声明的那个常量。
            // 再根据界面显示的内容,就可以发现上面声明的那个常量后面是一个平台鉴别的函数,鉴别当前使用的设备是iOS还是android以此来显示不同的内容
            <Text style={styles.instructions}>{instructions}</Text>
          </View>
        );
      }
    }
    
    // 根据StyleSheet.create可以知道这是一个函数,并且是创建了一个样式表的函数
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',  // 垂直居中
        alignItems: 'center',  // 水平居中
        backgroundColor: '#F5FCFF', // 背景色
      },
      welcome: {
        fontSize: 20,
        textAlign: 'center',
        margin: 10,
      },
      instructions: {
        textAlign: 'center',
        color: '#333333',
        marginBottom: 5,
      },
    });
    
    // 其实关于上面样式表声明的这种写法还是可以理解的,因为在原生iOS开发的时候,在初始化控件的时候我也采用过以下的写法,供大家参考,其原理我也不大清楚,按照我自己的理解,等号的右边就是一个有返回值的无名函数
    // 以下是iOS原生示例,非App.js中代码
    // 以下是iOS原生示例,非App.js中代码
    // 以下是iOS原生示例,非App.js中代码
    UIView *vv = ({
        UIView *v = [[UIView alloc] init];
        v.frame = CGRectMake(10, 10, 100, 44);
        v.backgroundColor = [UIColor redColor];
        // 这里可以声明很多控件组成的一个复杂控件,只需要在这里的最后返回这个复杂控件即可
        return v;
      });
    

    样式

    在RN当中,所有的界面样式都是使用JavaScript来实现的,所有的核心组件都接受名为style的属性,只是其中的样式名称命名做了改变,其余的均为改变。

    Style属性是一个普通的JavaScript对象,在这里使用的时候还可以传入一个数组,在数组中位置居后的样式对象比居前的优先级更高,这样可以间接实现样式的继承。

    实际开发中组件的样式会越来越复杂,我们可以使用StyleSheet.create来几种定义组件的样式,比如下面所示:

    import React, { Component } from 'react';
    import { AppRegistry, StyleSheet, Text, View } from 'react-native';
    
    export default class LotsOfStyles extends Component {
      render() {
        return (
          <View>
            // 这个Text定义的样式中只改变了显示文字的颜色为红色,其他均为默认
            <Text style={styles.red}>just red</Text>
            // 第二个Text的样式定义改变文字颜色为蓝色,粗体,字号30
            <Text style={styles.bigblue}>just bigblue</Text>
            // 第三个Text的样式定义改变文字颜色为蓝色,粗体,字号30,但是这里是一个数组,styles.red居后,优先级高,所以最终字体的显示效果为红色,粗体,字号30
            <Text style={[styles.bigblue, styles.red]}>bigblue, then red</Text>
            // 第四个Text的样式定义改变文字颜色为红色,但是styles.bigblue优先级更高,故最终显示效果为蓝色,粗体,字号30(后面的字体颜色优先级高于styles.red中定义的红色,故显示蓝色)
            <Text style={[styles.red, styles.bigblue]}>red, then bigblue</Text>
          </View>
        );
      }
    }
    
    const styles = StyleSheet.create({
      bigblue: {
        color: 'blue',
        fontWeight: 'bold',
        fontSize: 30,
      },
      red: {
        color: 'red',
      },
    });
    

    显示效果图如下:


    效果图

    高度与宽度

    最简单的给组件设定尺寸的方式就是在样式中指定固定数值的widthheight。RN中的尺寸都是无单位的,表示的是与设备像素密度无关的逻辑像素点。

    如下:

    import React, { Component } from 'react';
    import { AppRegistry, View } from 'react-native';
    
    export default class FixedDimensionsBasics extends Component {
      render() {
        return (
          <View>
            <View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
            <View style={{width: 100, height: 100, backgroundColor: 'skyblue'}} />
            <View style={{width: 150, height: 150, backgroundColor: 'steelblue'}} />
          </View>
        );
      }
    }
    

    效果图


    效果图

    除了指定具体数值的宽高设置,在组件样式中还可以使用flex来在可利用的空间中动态的扩张或收缩。一般而言我们会使用flex:1来指定某个组件扩张以撑满所有剩余的控件。如果有多个并列的子组件使用了flex:1,则这些子组件会平分父容器中剩余的控件。如果这些并列的子组件的flex值不一样,则谁的值更大,谁占据剩余空间的比例就更大(即占据剩余控件的比等于并列组件间flex值的比)

    如下示例:

    import React, { Component } from 'react';
    import { AppRegistry, View } from 'react-native';
    
    export default class FlexDimensionsBasics extends Component {
      render() {
        return (
          // 试试去掉父View中的`flex: 1`。
          // 则父View不再具有尺寸,因此子组件也无法再撑开。
          // 然后再用`height: 300`来代替父View的`flex: 1`试试看?
          <View style={{flex: 1}}>
            <View style={{flex: 1, backgroundColor: 'powderblue'}} />
            <View style={{flex: 2, backgroundColor: 'skyblue'}} />
            <View style={{flex: 3, backgroundColor: 'steelblue'}} />
          </View>
        );
      }
    }
    

    效果图:


    效果图

    使用Flexbox布局

    我们在RN中使用 flexbox 规则来指定某个组件的子元素的布局。Flexbox 可以在不同屏幕尺寸上提供一致的布局结构。

    一般来说,使用flexDirectionalignItemsjustifyContent三个样式属性就已经能满足大多数布局需求。

    Flex Direction

    在组件的style中指定flexDirection可以决定布局的主轴。
    row: 子元素沿着水平轴(row)方向排列
    column: 子元素沿着竖直轴(column)方向排列(默认值)

    示例如下

    import React, { Component } from 'react';
    import { AppRegistry, View } from 'react-native';
    
    export default class FlexDirectionBasics extends Component {
      render() {
        return (
          // 尝试把`flexDirection`改为`column`看看
          <View style={{flex: 1, flexDirection: 'row'}}>
            <View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
            <View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} />
            <View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
          </View>
        );
      }
    };
    
    效果图
    Justify Content

    在组件的 style 中指定justifyContent可以决定其子元素沿着主轴的排列方式。效果图均以flexDirection : 'column'为准

    以下代码,每次更换justifyContent的值,查看效果

    export default class JustifyContentBasics extends Component {
      render() {
        return (
            <View style = {{flex : 1, flexDirection : 'column', justifyContent : 'flex-start'}}>
              <View style = {{width : 50, height : 50, backgroundColor : 'powderblue'}} ><Text>1</Text></View>
              <View style = {{width : 50, height : 50, backgroundColor : 'skyblue'}} ><Text>2</Text></View>
              <View style = {{width : 50, height : 50, backgroundColor : 'steelblue'}} ><Text>3</Text></View>
            </View>
        );
      }
    };
    

    flex-start

    justifyContent : 'flex-start'

    center

    justifyContent : 'center'

    flex-end

    justifyContent : 'flex-end'

    space-around

    justifyContent : 'space-around'

    space-between

    justifyContent : 'space-between'

    space-evenly

    justifyContent : 'space-evenly'
    Align Items

    在组件的 style 中指定alignItems可以决定其子元素沿着次轴(与主轴垂直的轴,比如若主轴方向为row,则次轴方向为column)的排列方式。

    以下代码,以column纵轴为主轴,横轴为次轴,每次更换alignItems的值,查看效果

    import React, { Component } from 'react';
    import { AppRegistry, View } from 'react-native';
    
    export default class AlignItemsBasics extends Component {
      render() {
        return (
          <View style = {{flex : 1, flexDirection : 'column', justifyContent : 'center', alignItems : 'flex-start'}}>
              <View style = {{width : 50, height : 50, backgroundColor : 'powderblue'}} ><Text>1</Text></View>
              <View style = {{width : 50, height : 50, backgroundColor : 'skyblue'}} ><Text>2</Text></View>
              <View style = {{width : 50, height : 50, backgroundColor : 'steelblue'}} ><Text>3</Text></View>
           </View>
        );
      }
    };
    

    flex-start

    alignItems : 'flex-start'

    center

    alignItems : 'center'

    flex-end

    alignItems : 'flex-end'

    stretch

    注意:要使stretch选项生效的话,子元素在次轴方向上不能有固定的尺寸。

    要使stretch生效的话,子元素在次轴上方向上不能有固定的尺寸,即如果主轴为column,子元素不能有固定值的宽;代码如下:

    import React, { Component } from 'react';
    import { AppRegistry, View } from 'react-native';
    
    export default class AlignItemsBasics extends Component {
      render() {
        return (
          <View style = {{flex : 1, flexDirection : 'column', justifyContent : 'center', alignItems : 'flex-start'}}>
              <View style = {{height : 50, backgroundColor : 'powderblue'}} ><Text>1</Text></View>
              <View style = {{height : 50, backgroundColor : 'skyblue'}} ><Text>2</Text></View>
              <View style = {{height : 50, backgroundColor : 'steelblue'}} ><Text>3</Text></View>
           </View>
        );
      }
    };
    
    alignItems : 'stretch'

    属性(Props)

    在OC开发中,当我们自定义一个组件的时候,肯定要对外暴露部分的属性或者方法,以此来增加组件的兼容性,能够让使用者对组件的颜色、内容等可以定制化开发。

    在React Native中的大多数组件在创建时就可以使用各种参数来定制。用于定制的这些参数就成为props(属性)。

    比如基础组件Image,在创建图片的时候传入一个名为source的prop来指定要显示的图片的地址,传入一个名为style的prop来控制其尺寸大小。

    import React, { Component } from 'react';
    import { Image } from 'react-native';
    
    export default class Bananas extends Component {
      render() {
        let pic = {
          uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg'
        };
        return (
          <Image source={pic} style={{width: 193, height: 110}} />
        );
      }
    }
    

    注意:{pic}外围有一层大括号,大括号的意思是说在大括号内部是一个js变量或者表达式,需要执行后取值。

    以上说的是自带的基础组件,当然我们也可以像在OC中一样,自定义自己需要的组件,这时候我们也可以为自己的组件定义prop,当在调用的时候,就可以在父组件中指定其值。如下:

    // 此为一个js文件
    import React, { Component } from 'react';
    import { Text, View } from 'react-native';
    
    // 在RN的一个js文件中,可以有很多形如 “class 组件名 extends Component” 的组件声明
    class Greeting extends Component {
      render() {
        return (
          <Text>Hello {this.props.name}!</Text>
        );
      }
    }
    
    // 在RN的一个js文件中,必须要只有一个下面的默认组件声明,这个声明可以理解为一个文件的入口函数
    export default class LotsOfGreetings extends Component {
      render() {
        return (
          <View style={{alignItems: 'center'}}>
            // 这里是引用上面定义的Greeting组件,其中name是其属性,在其内部使用this.props.name引用父组件设置的值
            <Greeting name='Rexxar' />
            <Greeting name='Jaina' />
            <Greeting name='Valeera' />
          </View>
        );
      }
    }
    

    状态(State)

    我们使用两种数据来控制一个组件:propsstateprops是在父组件中指定,而且一经指定,在被指定的组件的声明周期中则不再改变。对于需要改变的数据,我们需要使用state

    就像我们在iOS原生中请求网络数据一样,在得到服务器返回的数据后,我们就会进行赋值、刷新界面等操作。在React Native中,我们可以直接使用state,一般来说,我们首先需要在constructor中初始化state,然后在需要修改时(如收到服务器返回的数据时)调用setState方法,在每次调用setState时,系统会重新执行render方法重新渲染界面。

    注意:

    • 一切界面变化都是状态state变化
    • state的修改必须通过setState()方法
    • setState是一个merge合并操作,只修改指定属性,不影响其他属性
    • setState是异步操作,修改不会马上生效

    结束语

    关于React Native的入门介绍其实并不是很多,如果是从事网站开发的人员入手会更加的简单快速,这对于App开发人员来说也不是特别难的一件事,当然,关于这些入门的懂了之后,剩下的就是研究一下React Native的基础组件的使用、生命周期函数、一些特别的写法等问题,在接下来的空闲时间,我也会一一列举这些知识,希望能够帮到更多的人。

    相关文章

      网友评论

          本文标题:React Native 入门介绍

          本文链接:https://www.haomeiwen.com/subject/hsfnnftx.html