React學習:狀態(State) 和 屬性(Props)

簡介

大多數組件在創建時就可以使用各種參數來進行定製。用於定製的這些參數就稱爲props(屬性)。
我們使用兩種數據來控制一個組件:props和state。props是在父組件中指定,而且一經指定,在被指定的組件的生命週期中則不再改變。 對於需要改變的數據,我們需要使用state。

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}外圍有一層括號,我們需要用括號來把pic這個變量嵌入到JSX語句中。括號的意思是括號內部爲一個js變量表達式,需要執行後取值。因此我們可以把任意合法的JavaScript表達式通過括號嵌入到JSX語句中。
當然你也可以寫成這樣

import React, { Component } from 'react';
import {
  Image
} from 'react-native';

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

Image組件用於顯示圖片;
source屬性指定顯示圖片的地址,有兩種指定形式:
 指定本機文件:source={require('./icon.png')},,相對位置尋址
  注:: 如果你有my-icon.ios.pngmy-icon.android.pngPackager就會根據平臺而選擇不同的文件。
 指定網絡圖片:source={{uri: 'http://facebook.github.io/react/img/logo_og.png'}}
  注:: 一般需要手動指定圖片的尺寸 style={{widtn:193,height:110}}
下面是指定本機文件的寫法

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

export default class APP extends Component {
    render() {
        return(
            <View>
                <Image source={require('./img/guide.png')} />
            </View>
        );
    }
}

自定義的組件也可以使用props。通過在不同的場景使用不同的屬性定製,可以儘量提高自定義組件的複用範疇。只需在render函數中引用this.props,然後按需處理即可。
下面的例子把Greeting組件寫在JSX語句中,用法和內置組件並無二致,我們在Greeting組件中將name作爲一個屬性來定製,這樣可以複用這一組件來製作各種不同的“問候語”。

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

//在組件中,獲取屬性的方法如下代碼:
class Greeting extends Component {
//每一個組件中必須有一個render方法,用於輸出組件
    render() {
//使用return來返回要輸出的內容
        return (
            <Text>Hello {this.props.name}!</Text>
        );
    }
}

//定義屬性:
export default class App extends Component {
    render() {
        return (
            <View style={{alignItems: 'center'}}>
                <Greeting name='zhang' />
                <Greeting name='wang' />
                <Greeting name='zhao' />
            </View>
        );
    }
}

組件的用法與原生的 HTML 標籤完全一致,可以任意加入屬性,比如<Greeting name="wang">,就是Greeting組件加入一個name屬性,值爲wang。組件的屬性可以在組件類的this.props對象上獲取,比如name屬性就可以通過this.props.name讀取。

State(狀態)

我們使用兩種數據來控制一個組件:屬性(props)狀態(state)屬性(props)是在父組件中指定,而且一經指定,在被指定的組件的生命週期中則不再改變。 對於需要改變的數據,我們需要使用狀態(state)

一般來說,你需要在constructor中初始化狀態(state(譯註:這是ES6的寫法,早期的很多ES5的例子使用的是getInitialState方法來初始化state,這一做法會逐漸被淘汰),然後在需要修改時調用setState方法。

假如我們需要製作一段不停閃爍的文字。文字內容本身在組件創建時就已經指定好了,所以文字內容應該是一個屬性(prop)。而文字的顯示或隱藏的狀態(快速的顯隱切換就產生了閃爍的效果)則是隨着時間變化的,因此這一狀態應該寫到狀態(state)中。

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

class Blink extends Component {
    //constructor 構造函數
    constructor(props) {
        super(props);  //執行父類的方法
        this.state = { showText: true };

        // 每1000毫秒對showText狀態做一次取反操作
        setInterval(() => {
            this.setState(previousState => {
                return { showText: !previousState.showText };
            });
        }, 1000);
    }

    render() {
        // 根據當前showText的值決定是否顯示text內容
        let display = this.state.showText ? this.props.text : ' ';
        return (
            <Text>{display}</Text>
        );
    }
}

export default class BlinkApp extends Component {
    render() {
        return (
            <View>
                <Blink text='I love to blink' />
                <Blink text='Yes blinking is so great' />
                <Blink text='Why did they ever take this out of HTML' />
                <Blink text='Look at me look at me look at me' />
            </View>
        );
    }
}

constructor

我覺得在這裏有必要介紹一下constructor屬性,當你在React class中需要設置state的初始值或者綁定事件時,需要加上constructor(){}
我們知道,在JavaScript中,constructor返回對創建此對象的數組函數的引用。
例程如下,前者輸出內容,後着輸出整個 constructor構造函數

<script type="text/javascript">

var test=new Array();

if (test.constructor==Array)
{
document.write("This is an Array");
}

if (test.constructor==Date)
{
document.write("This is a Date");
}

</script>

輸出結果:This is an Array
<script type="text/javascript">

function employee(name,job,born)
{
this.name=name;
this.job=job;
this.born=born;
}

var bill=new employee("Bill Gates","Engineer",1985);
document.write(bill.constructor);

</script>
輸出結果:function employee(name,job,born) { this.name=name; this.job=job; this.born=born; }

而在react-native中,用法是稍微有些區別的
onstructor方法中出現了super關鍵字,它在這裏表示父類的構造函數,用來新建父類的this對象,子類必須在constructor方法中調用super方法,否則新建實例時會報錯,因爲子類沒有自己的this對象,而是繼承父類的this對象,然後對其進行加工。如果不調用super方法,子類就得不到this對象

取反操作

// 每1000毫秒對showText狀態做一次取反操作
        setInterval(() => {
            this.setState(previousState => {
                return { showText: !previousState.showText };
            });
        }, 1000);

這裏其實就是將this.state的值作爲一個參數previousState傳了進去,previousState.showTextthis.state.showText是等價的;然後要通過return方法把值返回給state,不然這個showText只是作爲形參,不對外面的state產生影響。在這裏previousState只起到中轉作用,你可以把它改爲任意值,不影響效果,就像下面這樣

this.setState(aa => {
                return { showText: !aa.showText };
            });

當然如果覺得不好理解的話,也可以直接用下面這種寫法
this.setState({showText: !this.state.showText});

State的工作原理和React.js完全一致,所以對於處理state的一些更深入的細節,你可以參閱React.Component API。不過上面那個英文版的看着不方便,如果想學習更多關於react的知識的話,所以強烈推薦極客學院的中文版本

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章