React Native 快速入门

React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的UI框架 React 在原生移动应用平台的衍生产物,目前支持iOS和安卓两大平台。RN使用Javascript语言,类似于HTML的JSX,以及CSS来开发移动应用,因此熟悉Web前端开发的技术人员只需很少的学习就可以进入移动应用开发领域。

一、从 ES6 开始

  1. const、let 关键字

    • let:众所周知 JavaScript 中变量默认是全局的,只存在函数级作用域。ES6中提出 let 关键字,使JavaScript 也有了块级作用域。

    • const:用来定义常量,一旦定以后不可修改,但是可以修改属性。

      const MYNAME = {foo: 'Ginger'};
      MYNAME.foo = 'Zoe';
      
  2. 函数

    • 箭头函数
      可以看做是一种语法糖,箭头函数永远是匿名的

      let add = (a, b) => {return a + b;}
      // 当后面是表达式的时候,还可以简写成
      let add = (a, b) => a + b;
      // 等同于
      let add = function(a, b){
        return a + b;
      }
      // 在回调函数中的应用
      let numbers = [1, 2, 3];
      let doubleNumbers = numbers.map((number) => number * 2); // [2, 4, 6]
      
    • this 在箭头函数中的使用
      在对象方法的嵌套函数中,this 会指向 global。

      let age = 2;
      let kitty = {
        age: 1,
        grow: function() {
          setTimeout(function() {
            console.log(++this.age);
          }, 100);
        }
      }
      kitty.grow(); // 3
      
      // 一般的解决方法
      let kitty = {
        age: 1,
        grow: function() {
          setTimeout(function() {
            console.log(++this.age);
          }.bind(this), 100);
        }
      }
      // 或者
      let kitty = {
        age: 1,
        grow: function() {
          const self = this;
          setTimeout(function() {
            console.log(++self.age);
          }.bind(this), 100);
        }
      }
      
      // 有了箭头函数这个问题就可以轻松解决了
      let kitty = {
        age: 1,
        grow: function() {
          setTimeout(() => {
            console.log(++this.age);
          }, 100);
        }
      }
      
    • 默认参数函数

      function desc(name = 'Ginger', age = 18){
        return name + ' is ' + age + ' years old';
      }
      desc();
      //Ginger is 18 years old
      
    • Rest 参数
      当一个函数的最后一个参数有“…”这样的前缀,它就会变成一个参数的数组。

      function test(...args){
        console.log(args);
      }
      
      test(1, 2, 3);
      //[1, 2, 3]
      
      function test2(name, ...args){
        console.log(args);
      }
      
      test2('Ginger', 2, 3);
      //[2, 3]
      

  3. 展开操作符(“…”)

    允许一个表达式在某处展开,在存在多个参数(用于函数调用)、多个元素(用于数组字面量)或者多个变量(用于结构赋值)的地方就会出现这种情况。

    • 用于函数调用

      // 之前,想让函数把一个数组作为依次作为参数调用方法如下
      function test(x, y, z) { };
      var args = [1, 2, 3];
      test.apply(null, args);
      
      // 有了 ES6 的展开运算符之后
      function test(x, y, z) { };
      let args = [1, 2, 3];
      test(...args);
      
    • 用于数组字面量
      在之前的版本中,想要创建含某些元素的新数组,常使用 splice、concat、push.

      var arr1 = [1, 2, 3];
      var arr2 = [4, 5, 6];
      var arr3 = arr1.concat(arr2);
      
      // 使用 ES6 之后
      let arr1 = [1, 2, 3];
      let arr2 = [4, 5, 6];
      let arr3 = [...arr1, ...arr2];
      
    • 对象的展开运算符

      let mike = {name: 'mike', age: 50};
      mike = {...mike, sex: 'male'};
      console.log(mike);
      // {name: 'mike', age: 50, sex: 'male'}
      
  4. 模板字符串(注意不是',是`)
    字符串拼接总是令人很不爽的一件事情,但是在 ES6 来临的时代,这个痛处也被治愈了。

    // 之前
    var name = 'Ginger';
    var a = 'My name is ' + Ginger + '!'
    // 多行
    var langStory = 'This is a long story,'
          + 'this is a long story,'
          + 'this is a long story.';
    // 有了 ES6 之后
    let name = 'Ginger';
    let a = `My name is ${name} !`;
    let longStory = `This is a long story,
                 this is a long story,
                 this is a long story`;
    
  5. 解构赋值

    • 解构数组

       let foo = ['one', 'two', 'three'];
       let [one, two, three] = foo;
      
       console.log(`${one}, ${two}, ${three}`);
       // one, two, three
      
    • 解构对象

         let person = {name: 'Ginger', age: 18};
         let {name, age} = person;
      
         console.log(`${name}, ${age}`);
         // Ginger, 18
      

  6. 提供了 class 这个语法糖。让开发者可以模仿其他语言类的声明方式。只是原型链方式的一种语法糖。

       class Animal {
         // 构造函数
         constructor (name, age) {
           this.name = name;
           this.age = age;
         }
         shout() {
           return `${name}, ${age}`;
         }
         // 静态方法
         static foo() {
           return 'here is a static method';
         }
       }
    
       const cow = new Animal('betty', 2);
       cow.shout(); // betty, 2
    
       Animal.foo(); // here is a static method
    
       class Dog extends Animal {
         constructor(name, age = 2, color = 'black') {
           // 在构造函数中可以直接调用 spuer 方法
           super(name, age);
           this.color = color;
         }
         shout(){
           // 非构造函数中不能直接调用 super 方法
           return `${name}, ${age}, ${color}`;
         }
       }
    

  7. 模块
    在 ES6 之前,JavaScript 并没有对模块做出任何定义,于是先驱者们创造了各种各样的规范来完成这个任务。比如 Require.js,CommonJS,browerify 等等。
    使用 import export 关键字来完成模块的导入和导出。
    还可以使用 default 关键字来默认导出。

二、再说说 React

特点:1. 组件化;2. JSX;3. 虚拟 DOM;

  1. JSX

    • JSX 不是必须的。类似一种语法糖。把标签型的写法转化成 React 提供的一个用来创建 ReactElement 的方法。

      let app = <h1 title = "My title">this is my title</h1>
      // jsx转换后的结果
      let app = React.createElement('h1', {title: 'my title', 'this is my title'});
      
    • HTML 标签与 React 组件
      HTML 标签第一个字母用小写表示。
      React 组件第一个字母用大写表示。
      JSX 语法使用第一个字母大小写来区分是一个普通的 HTML 标签还是一个 React 组件。

    • JavaScript 表达式
      当遇到{}这个表达式的情况下,里面的代码会被仿作 JavaScript 代码处理。
      当省略一个属性值的时候,JSX会自动把它的值认为是 true。

    • 注释
      JSX 注释沿用 JavaScript 的方法,需要注意的是,在子组件的位置需要用{}括起来。

      let component = (
        <div>
         {/*这里是一个注释!*/}
         <Headline />
        </div>
      );
      
    • JSX 属性扩散

      let props = {
        name: 'Ginger',
        age: 18
      }
      
      // 用这种方式可以将 name,age 全部载入进来
      let component = <Profile {...props} />
      
      // 值得注意的是,越靠后的属性会覆盖前面的属性
      let component = <Profile {...props} name='Zoe' />
      
  2. React 的生命周期

    实例化

    首次实例化

    • getDefaultProps
    • getInitialState
    • componentWillMount
    • render
    • componentDidMount

    实例化完成后的更新

    • getInitialState
    • componentWillMount
    • render
    • componentDidMount
    存在期

    组件已存在时的状态改变

    • componentWillReceiveProps
    • shouldComponentUpdate
    • componentWillUpdate
    • render
    • componentDidUpdate
    销毁&清理期
    • componentWillUnmount
    说明

    生命周期共提供了10个不同的API。

    1.getDefaultProps

    作用于组件类,只调用一次,返回对象用于设置默认的props,对于引用值,会在实例中共享。

    2.getInitialState

    作用于组件的实例,在实例创建时调用一次,用于初始化每个实例的state,此时可以访问this.props

    3.componentWillMount

    在完成首次渲染之前调用,此时仍可以修改组件的state。

    4.render

    必选的方法,创建虚拟DOM,该方法具有特殊的规则:

    • 只能通过this.propsthis.state访问数据
    • 可以返回nullfalse或任何React组件
    • 只能出现一个顶级组件(不能返回数组)
    • 不能改变组件的状态
    • 不能修改DOM的输出
    5.componentDidMount

    真实的DOM被渲染出来后调用,在该方法中可通过this.getDOMNode()访问到真实的DOM元素。此时已可以使用其他类库来操作这个DOM。比如 AJAX 请求可以放在这里。

    在服务端中,该方法不会被调用。

    6.componentWillReceiveProps

    组件接收到新的props时调用,并将其作为参数nextProps使用,此时可以更改组件propsstate

        componentWillReceiveProps: function(nextProps) {
            if (nextProps.bool) {
                this.setState({
                    bool: true
                });
            }
        }
    
    7.shouldComponentUpdate

    组件是否应当渲染新的propsstate,返回false表示跳过后续的生命周期方法,通常不需要使用以避免出现bug。在出现应用的瓶颈时,可通过该方法进行适当的优化。

    在首次渲染期间或者调用了forceUpdate方法后,该方法不会被调用

    8.componentWillUpdate

    接收到新的props或者state后,进行渲染之前调用,此时不允许更新propsstate

    9.componentDidUpdate

    完成渲染新的props或者state后调用,此时可以访问到新的DOM元素。不能再该状态下 setState 等,会造成组件死循环。

    10.componentWillUnmount

    组件被移除之前被调用,可以用于做一些清理工作,在componentDidMount方法中添加的所有任务都需要在该方法中撤销,比如创建的定时器或添加的事件监听器。

  3. 组件
    先来一个简单的例子。

    import React from 'react';
    
    class List extends React.Component {
      // 在 ES6 中不再使用getInitialState而使用constructor
      constructor(props) {
        super(props);
        this.state = ['a', 'b', 'c'];
      }
      
      render(){
        return (...);
      }
    }
    
    • props 属性
      可以看做是组件的数据来源。
      要想子组件传递数据需要通过 props 来完成

    • state 状态
      state 是组件内部的属性。
      当 state 的值发生改变的时候,可以调用 this.setState 方法让组件再次调用 render 方法,重新渲染 UI。
      state 中应该包含组件的事件回调函数可能引发 UI 更新的这类数据。

    • 引入组件
      将组件的文件引入,再在新的组件中加入已经写好的组件标签。

      import React from 'react';
      import List from './list';
      
      class Profile extends React.Component {
        // 在 ES6 中不再使用getInitialState而使用constructor
        constructor(props) {
          super(props);
        }
        
        render(){
          return (
            <List />
          );
        }
      }
      

三、让我们开始 React Native 的旅程

  1. 快速开始
    参考网站:http://reactnative.cn/docs/0.41/getting-started.html
    事先搭建好开发环境。快速开始:react-native init HelloRN
    进入这个 HelloRN 文件夹后,里面有两个入口文件: index.ios.js index.android.js,修改入口文件内容刷新模拟器,即可看到你写的内容~

  2. flexbox 布局
    我们在React Native中使用flexbox规则来指定某个组件的子元素的布局。Flexbox可以在不同屏幕尺寸上提供一致的布局结构。
    一般来说,使用flexDirectionalignItemsjustifyContent三个样式属性就已经能满足大多数布局需求。
    摘自网上总结的很好的 flex 布局口诀图。(http://weibo.com/1712131295/CoRnElNkZ?ref=collection&type=comment#_rnd1488247287265

    flex1.jpg

    flex2.jpg

    flex3.jpg

    flex4.jpg

    flex5.jpg

  3. 常用组件介绍
    入口文件说明

    import React, { Component } from 'react';
    import {
      AppRegistry,
      StyleSheet,
      Text,
      View
    } from 'react-native'; // 将使用到的 react-native 组件引入
    
    export default class reactNative extends Component {
      render() {
        return (
          //  View 组件相当于 html 的 div。可以视作一个包裹内容的容器。
          <View style={styles.container}>
             // 所有的文字内容都需要被包裹在 Text 标签中
            <Text style={styles.welcome}>
              Welcome to React Native!
            </Text>
             // 若要直接在组件中写入样式 <Text style={{textAlign: 'center'}}>。注意是 {{}}
            <Text style={styles.instructions}>
              To get started, edit index.ios.js
            </Text>
            <Text style={styles.instructions}>
              Double tap R on your keyboard to reload,{'\n'}
              Shake or press menu button for dev menu
            </Text>
          </View>
        );
      }
    }
    
    // StyleSheet提供了一种类似CSS样式表的抽象。RN 中样式使用驼峰格式。
    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,
      },
    });
    
    AppRegistry.registerComponent('reactNative', () => reactNative);
    // AppRegistry是JS运行所有React Native应用的入口。应用的根组件应当通过AppRegistry.registerComponent方法注册自己,然后原生系统才可以加载应用的代码包并且在启动完成之后通过调用AppRegistry.runApplication来真正运行应用。
    
    • View
      类似于 html 中的 div,盒子布局,将内容包裹在里面。

    • Text
      所有的文字都必须要放在 Text 标签中。

    • Image

    renderImages() {
      return (
        <View>
          // 本地模式
          <Image
            style={styles.icon}
            source={require('./icon.png')}
          />
          // 使用网络资源
          <Image
            style={styles.logo}
            source={{uri: 'http://facebook.github.io/react/img/logo_og.png'}}
          />
        </View>
      );
    }
    

    ​ 至此,关于 React Native 的基础说明完成。赶快开始在 index.ios.js 中涂涂画画吧~

  4. 其他常用组件

    • NavigatorIOS
      该组件本质上是对 UIKit navigation 的包装。也就是说,使用 NavigatorIOS 进行路由切换,实质上是调用了UIKit的navigation。


      navigation.jpeg
    • TextInput
      通过键盘将文本输入到 app 的组件。

    • Touchable
      RN 没有像 web 开发那样可以个元素绑定 click 时间。Text 组件中可以使用 onPress 事件绑定触摸点击事件。为了使其他组件也可以被点击,提供了3个组件来做这个事情。这3个组件被称为“Touchable类组件”。

    • TarBarIOS
      为切换不同页面


      TarBar.jpeg
    • WebView

赶快动手试试这些组件吧~

参考内容:
http://reactnative.cn/docs/0.41/getting-started.html
《React 全栈》
《React Native 入门与实战》

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

推荐阅读更多精彩内容