Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> React Native之React速學教程(下)

React Native之React速學教程(下)

編輯:關於Android編程

React Native是基於React的,在開發React Native過程中少不了的需要用到React方面的知識。雖然官方也有相應的Document,但篇幅比較多,學起來比較枯燥。
通過《React Native之React速學教程》你可以對React有更系統和更深入的認識。為了方便大家學習,我將《React Native之React速學教程》分為上、中、下三篇,大家可以根據需要進行閱讀學習。

概述

本篇為《React Native之React速學教程》的最後一篇。本篇將帶著大家一起認識ES6,學習在開發中常用的一些ES6的新特性,以及ES6與ES5的區別,解決大家在學習React /React Native過程中對於ES6與ES5的一些困惑。

ES6的特性

何為ES6?

ES6全稱ECMAScript 6.0,ES6於2015年6月17日發布,ECMAScript是ECMA制定的標准化腳本語言。目前JavaScript使用的ECMAScript版本為ECMAScript-262。

下面我為大家列舉了ES6新特性中對我們開發影響比較大的六方面的特性。

1.類(class)

對熟悉Java,object-c,c#等純面向對象語言的開發者來說,都會對class有一種特殊的情懷。ES6 引入了class(類),讓JavaScript的面向對象編程變得更加簡單和易於理解。

  class Animal {
    // 構造方法,實例化的時候將會被調用,如果不指定,那麼會有一個不帶參數的默認構造函數.
    constructor(name,color) {
      this.name = name;
      this.color = color;
    }
    // toString 是原型對象上的屬性
    toString() {
      console.log('name:' + this.name + ',color:' + this.color);

    }
  }

 var animal = new Animal('dog','white');//實例化Animal
 animal.toString();

 console.log(animal.hasOwnProperty('name')); //true
 console.log(animal.hasOwnProperty('toString')); // false
 console.log(animal.__proto__.hasOwnProperty('toString')); // true

 class Cat extends Animal {
  constructor(action) {
    // 子類必須要在constructor中指定super 方法,否則在新建實例的時候會報錯.
    // 如果沒有置頂consructor,默認帶super方法的constructor將會被添加、
    super('cat','white');
    this.action = action;
  }
  toString() {
    console.log(super.toString());
  }
 }

 var cat = new Cat('catch')
 cat.toString();

 // 實例cat 是 Cat 和 Animal 的實例,和Es5完全一致。
 console.log(cat instanceof Cat); // true
 console.log(cat instanceof Animal); // true

2.模塊(Module)

ES5不支持原生的模塊化,在ES6中,模塊將作為重要的組成部分被添加進來。模塊的功能主要由 export 和 import 組成。每一個模塊都有自己單獨的作用域,模塊之間的相互調用關系是通過 export 來規定模塊對外暴露的接口,通過import來引用其它模塊提供的接口。同時還為模塊創造了命名空間,防止函數的命名沖突。

導出(export)

ES6允許在一個模塊中使用export來導出多個變量或方法。

導出變量

//test.js
export var name = 'Rainbow'

心得:ES6不僅支持變量的導出,也支持常量的導出。 export const sqrt = Math.sqrt;//導出常量

ES6將一個文件視為一個模塊,上面的模塊通過 export 向外輸出了一個變量。一個模塊也可以同時往外面輸出多個變量。

 //test.js
 var name = 'Rainbow';
 var age = '24';
 export {name, age};

導出函數

// myModule.js
export function myModule(someArg) {
  return someArg;
}  

導入(import)

定義好模塊的輸出以後就可以在另外一個模塊通過import引用。

import {myModule} from 'myModule';// main.js
import {name,age} from 'test';// test.js

心得:一條import 語句可以同時導入默認方法和其它變量。import defaultMethod, { otherMethod } from 'xxx.js';

3.箭頭(Arrow)函數

這是ES6中最令人激動的特性之一。=>不只是關鍵字function的簡寫,它還帶來了其它好處。箭頭函數與包圍它的代碼共享同一個this,能幫你很好的解決this的指向問題。有經驗的JavaScript開發者都熟悉諸如var self = this;或var that = this這種引用外圍this的模式。但借助=>,就不需要這種模式了。

箭頭函數的結構

箭頭函數的箭頭=>之前是一個空括號、單個的參數名、或用括號括起的多個參數名,而箭頭之後可以是一個表達式(作為函數的返回值),或者是用花括號括起的函數體(需要自行通過return來返回值,否則返回的是undefined)。

// 箭頭函數的例子
()=>1
v=>v+1
(a,b)=>a+b
()=>{
    alert("foo");
}
e=>{
    if (e == 0){
        return 0;
    }
    return 1000/e;
}

心得:不論是箭頭函數還是bind,每次被執行都返回的是一個新的函數引用,因此如果你還需要函數的引用去做一些別的事情(譬如卸載監聽器),那麼你必須自己保存這個引用。

卸載監聽器時的陷阱

錯誤的做法

class PauseMenu extends React.Component{
    componentWillMount(){
        AppStateIOS.addEventListener('change', this.onAppPaused.bind(this));
    }
    componentDidUnmount(){
        AppStateIOS.removeEventListener('change', this.onAppPaused.bind(this));
    }
    onAppPaused(event){
    }
}

正確的做法

class PauseMenu extends React.Component{
    constructor(props){
        super(props);
        this._onAppPaused = this.onAppPaused.bind(this);
    }
    componentWillMount(){
        AppStateIOS.addEventListener('change', this._onAppPaused);
    }
    componentDidUnmount(){
        AppStateIOS.removeEventListener('change', this._onAppPaused);
    }
    onAppPaused(event){
    }
}

除上述的做法外,我們還可以這樣做:

class PauseMenu extends React.Component{
    componentWillMount(){
        AppStateIOS.addEventListener('change', this.onAppPaused);
    }
    componentDidUnmount(){
        AppStateIOS.removeEventListener('change', this.onAppPaused);
    }
    onAppPaused = (event) => {
        //把方法直接作為一個arrow function的屬性來定義,初始化的時候就綁定好了this指針
    }
}

需要注意的是:不論是bind還是箭頭函數,每次被執行都返回的是一個新的函數引用,因此如果你還需要函數的引用去做一些別的事情(譬如卸載監聽器),那麼你必須自己保存這個引用。

4.ES6不再支持Mixins

在ES5下,我們經常使用mixin來為組件添加一些新的方法,如:

var SetIntervalMixin = {
  componentWillMount: function() {
    this.intervals = [];
  },
  setInterval: function() {
    this.intervals.push(setInterval.apply(null, arguments));
  },
  componentWillUnmount: function() {
    this.intervals.forEach(clearInterval);
  }
};
var TickTock = React.createClass({
  mixins: [SetIntervalMixin], // Use the mixin
  getInitialState: function() {
    return {seconds: 0};
  },
  ...

但,很不幸的是,ES6不支持使用Mixins了,不過我們可以使用,增強組件來替代Mixins。

//Enhance.js
import { Component } from "React";

export var Enhance = ComposedComponent => class extends Component {
    constructor() {
        this.state = { data: null };
    }
    componentDidMount() {
        this.setState({ data: 'Hello' });
    }
    render() {
        return ;
    }
};
//HigherOrderComponent.js
import { Enhance } from "./Enhance";

class MyComponent {
    render() {
        if (!this.data) returnWaiting...;
        return{this.data};
    }
}

export default Enhance(MyComponent); // Enhanced component

用一個“增強組件”,來為某個類增加一些方法,並且返回一個新類,這無疑能實現mixin所實現的大部分需求。

另外,網上也有很多其他的方案,如react-mixin。

5.ES6不再有自動綁定

在ES5中,React.createClass會把所有的方法都bind一遍,這樣可以提交到任意的地方作為回調函數,而this不會變化。但在ES6中沒有了自動綁定,也就是說,你需要通過bind或者箭頭函數來手動綁定this引用。

// 通過使用 bind() 來綁定`this`
// 也可通過使用箭頭函數來實現 this.tick()}>

心得: 因為無論是箭頭函數還是bind()每次被執行都返回的是一個新的函數引用,所以,推薦大家在組件的構造函數中來綁定this。

``javascript
constructor(props) {
super(props);
this.state = {count: props.initialCount};
this.tick = this.tick.bind(this);//在構造函數中綁定this`
}
// 使用

 

### 6.static關鍵字

在ES6中我們可以通過static關鍵字來定義一個類函數。  

```javascript
class People {
    constructor(name) { //構造函數
          this.name = name;
    }
    sayName() {
          console.log(this.name);
    }
    static formatName(name) //將formatName定義為類方法
        return name[0].toUpperCase() + name.sustr(1).toLowerCase();
    }
}





console.log(People.formatName("tom")); //使用類方法formatName





ES6 VS ES5(ES6與ES5的區別)

新版本的React /React Native使用了ES6標准,下面就讓我們一起了解一下基於ES6的React/React Native相比ES5有哪些不同。

心得:很多React/React Native的初學者經常會被ES6問題迷惑:官方建議我們ES6,但是網上搜到的很多教程和例子都是基於ES5版本的,所以很多人感覺無法下手,下面就讓我們一起認識ES6與ES5在React/React Native開發上有哪些不同和需要注意的地方。

下面是我們需要知道的ES6與ES5在4大方面上的區別。

1.在定義方面的不同

在定義組件,方法,屬性等方面,ES6與ES5是有所不同的,下面就讓我們一起看一下有哪些不同。

心得:因為向下兼容的原因,你在開發過程中可使用ES6也可以使用ES5的規范,但為了代碼的風格一致性,建議盡量減少混寫。

定義組件

ES5

在ES5裡,通常通過React.createClass來定義一個組件類,像這樣:

var Photo = React.createClass({
    render: function() {
        return (
            
        );
    },
});





ES6

在ES6裡,我們通過繼承React.Component 來定義一個組件類,像這樣:

class Photo extends React.Component {
    render() {
        return (
            
        );
    }
}





定義方法

相比ES5,ES6在方法定義上語法更加簡潔,從上面的例子裡可以看到,給組件定義方法不再用 名字: function()的寫法,而是直接用名字(),在方法的最後也不能有逗號了。

ES5

var Photo = React.createClass({
    test: function(){
    },
    render: function() {
        return (
            
        );
    },
});





ES6

class Photo extends React.Component {
    test() {
    }
    render() {
        return (
            
        );
    }
}





定義組件的屬性類型和默認屬性

ES5

在ES5裡,屬性類型和默認屬性分別通過propTypes成員和getDefaultProps方法來實現。

var Video = React.createClass({
    getDefaultProps: function() {
        return {
            autoPlay: false,
            maxLoops: 10,
        };
    },
    propTypes: {
        autoPlay: React.PropTypes.bool.isRequired,
        maxLoops: React.PropTypes.number.isRequired,
        posterFrameSrc: React.PropTypes.string.isRequired,
        videoSrc: React.PropTypes.string.isRequired,
    },
    render: function() {
        return (
            
        );
    },
});





ES6

在ES6裡,可以統一使用static成員來實現。

class Video extends React.Component {
    static defaultProps = {
        autoPlay: false,
        maxLoops: 10,
    };  // 注意這裡有分號
    static propTypes = {
        autoPlay: React.PropTypes.bool.isRequired,
        maxLoops: React.PropTypes.number.isRequired,
        posterFrameSrc: React.PropTypes.string.isRequired,
        videoSrc: React.PropTypes.string.isRequired,
    };  // 注意這裡有分號
    render() {
        return (
            
        );
    } // 注意這裡既沒有分號也沒有逗號
}





也有人這麼寫,雖然不推薦,但讀到代碼的時候你應當能明白它的意思:

class Video extends React.Component {
    render() {
        return (
            
        );
    }
}
Video.defaultProps = {
    autoPlay: false,
    maxLoops: 10,
};
Video.propTypes = {
    autoPlay: React.PropTypes.bool.isRequired,
    maxLoops: React.PropTypes.number.isRequired,
    posterFrameSrc: React.PropTypes.string.isRequired,
    videoSrc: React.PropTypes.string.isRequired,
};





心得:對React開發者而言,static在一些老版本的浏覽器上是不支持的。React Native開發者可以不用擔心這個問題。

2.在導入(import)與導出(export)組件上的不同

導入組件

ES5

在ES5裡,如果使用CommonJS標准,引入React包基本通過require進行,代碼類似這樣:

var React = require("react");
var {
    Component,
    PropTypes
} = React;  //引用React抽象組件





var ReactNative = require("react-native");
var {
    Image,
    Text,
} = ReactNative;  //引用具體的React Native組件





var AboutPage=require('./app/AboutPage') //引入app目錄下AboutPage組件,即AboutPag.js
var PopularPage=require('./app/PopularPage') //引入app目錄下PopularPage組件,即PopularPage.js
var FavoritePage=require('./app/FavoritePage') //引入app目錄下FavoritePage組件,即FavoritePage.js





ES6

在ES6裡,沒有了require,而是使用import來導入組件,有點像Java的寫法。

import React, { 
    Component,
    PropTypes,
} from 'react';//引用React抽象組件





import {
    Image,
    Text
} from 'react-native' //引用具體的React Native組件





import AboutPage from './app/AboutPage' //引入app目錄下AboutPage組件,即AboutPag.js
import PopularPage from './app/PopularPage' //引入app目錄下PopularPage組件,即PopularPage.js
import FavoritePage  from './app/FavoritePage' //引入app目錄下FavoritePage組件,即FavoritePage.js





另外,ES6支持將組件導入作為一個對象,使用“ * as”修飾即可。

//引入app目錄下AboutPage組件作為一個對象,接下來就可使用“AboutPage.”來調用AboutPage的方法及屬性了。  
import  * as AboutPage from './app/AboutPage' 





心得:使用“ * as ”修飾後,導入的組件直接被實例化成一個對象,可以使用“.”語法來調用組件的方法和屬性,和沒有“ * as ”修飾是有本質區別的,使用的時候要特別注意。

導出組件

ES5
在ES5裡,要導出一個類給別的模塊用,一般通過module.exports來導出:

var MyComponent = React.createClass({
    ...
});
module.exports = MyComponent;





ES6
在ES6裡,通常用export default來實現相同的功能:

export default class MyComponent extends Component{
    ...
}





3.在初始化state上的不同

ES5

var Video = React.createClass({
    getInitialState: function() {
        return {
            loopsRemaining: this.props.maxLoops,
        };
    },
})





ES6
ES6下,有兩種寫法:

class Video extends React.Component {
    state = {
        loopsRemaining: this.props.maxLoops,
    }
}





不過我們推薦更易理解的在構造函數中初始化(這樣你還可以根據需要做一些計算):

class Video extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            loopsRemaining: this.props.maxLoops,
        };
    }
}





4.在方法作為回調上的不同

在開發工作中,經常會使用到回調,如按鈕的單擊回調等,這也是在很多編程語言中都會經常出現的情況。ES6與ES5在使用回調方面是有區別的。

ES5

var PostInfo = React.createClass({
    handleOptionsButtonClick: function(e) {
        // Here, 'this' refers to the component instance.
        this.setState({showOptionsModal: true});
    },
    render: function(){
        return (
            
                {this.props.label}
            
        )
    },
});





在ES5中,React.createClass會把所有的方法都bind一遍,這樣可以提交到任意的地方作為回調函數,而this不會變化。但官方現在逐步認為這反而是不標准、不易理解的。

在ES6下,你需要通過bind來綁定this引用,或者使用箭頭函數(它會綁定當前scope的this引用):

ES6

class PostInfo extends React.Component{
    handleOptionsButtonClick(e){
        this.setState({showOptionsModal: true});
    }
    render(){
        return (
            this.handleOptionsButtonClick(e)}//這種方式和上面的效果是一樣的
                >
                {this.props.label}
            
        )
    },·
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved