• React Native 教程



    前言


    這個教程就是幫您加速如何使用 React native 開始iOS和 Android 的 apps 開發。如果您還不了解 React Native是什么,也不知道Facebook 為啥要研發這個,那這篇博客可以為您解釋。

    我們也假設您已經有用React 寫過應用程序的經驗。如果不是這樣,您可以在React 官方網站上了解到如何開始。

    基本設置:


    React native 需要一些基本的設置,這個我們在 React Native起步文章里面都已經做了介紹。

    在安裝完那些程序的依賴環境之后,這有兩條命令幫助您把 React Native 項目的開發環境也都設置好。

    npm install –g react-native-cli

    react-native-cli 是一個命令行接口,該程序會執行余下來的所有設置工作。 該命令行工具是通過npm 工具安裝的。這條命令就會所 react-native 做為一條命令安裝在您的終端命令行中。您只需執行一次這條命令就足夠了。

    React-native init AwesomeProject

    這條命令會從服務器上拿回 React Native 的資源代碼和一些附屬插件,然后會在AwesomeProject/iOS/AwesomeProject.xcodeproj 里創建一個新的XCode 項目,并且在AwesomeProject/android/app創建一個 gradle項目。

    開發


    對于 iOS,  您現在就可以在 XCode (AwesomeProject/ios/AwesomeProject.xcodeproj)里直接打開這個新的項目了,直接通過 ?+R就可以開始編譯運行這個程序了。在執行這個命令的同時,系統也會啟動一個 Node 服務器,該服務器也支持實時代碼加載。所以有了這個功能您就可以隨時通過點按 ?+R在您的模擬器中查看代碼的改變,而不需要在 XCode里面重新編譯。

    對于Android 用戶,在 AwesomeProject 中運行 react-native run-android,把生成的 app文件安裝在您的模擬器或是設備之上,同時也要啟動Node服務器以保證可以進行實時代碼加載。要看您的修改是否生效,您可以打開 rage-shake-menu(要不就是晃動設置或者就是按設置上的菜單按鈕,或者按 F2,在模擬器上面是按 Page Up, 在 Genymotion里面是按?+M),然后再按下重新加載JS.

    我們要做的這個例子是一個電影 app,會從數據庫里面拿下來 25 部正在電影院上映的電影然后用列表組件的形式展示出來。

    Hello World.


    React-native init 可以生成一個以你項目命名的 app,在我們這個例子中叫做 AwesomeProject.  這就是一個簡單的Hello World app. 在 iOS中,您可以修改 index.ios.js 文件來改變 app,然后再點按 ?+R 在模擬器里面去看看這些變化。對于 Android, 您可以編輯 index.android.js 文件進行修改,然后在 rage shake菜單里點按 Reload JS 去看變化。

    模擬數據


    在我們真正的開發代碼去從爛柿子網站拿實際的數據之前,讓我們先模擬一些數據讓我們對 React Native有一個簡單的了解先。 對于 Facebook的習慣,一般都會在 JS 的文件頂部做變量定義, 就象下面所列出的文件一樣,但其實您可以根據您的習慣在任何地方定義變量。 把下面的代碼加入到您的 index.ios.js 或者是index.android.js中去:

    var MOCKED_MOVIES_DATA = [
      {title: 'Title', year: '2015', posters: {thumbnail: 'http://i.imgur.com/UePbdph.jpg'}},
    ];


    展示一部電影

    我們打算把電影的片名,上映時間以及電影縮略圖展示出來。 因為縮略圖是 React Native 中的一個圖片組件,所以加入圖片到下面 React 所需要的列表中去。

    var {
      AppRegistry,
      Image,
      StyleSheet,
      Text,
      View,
    } = React;


    現在可以修改 render 函數,就可以把上面所提到的那些參數都加入到前面那個您好世界的文件里去了:

     render: function() { var movie = MOCKED_MOVIES_DATA[0]; return ( <View style={styles.container}> <Text>{movie.title}</Text> <Text>{movie.year}</Text> <Image source={{uri: movie.posters.thumbnail}} /> </View> ); }

    按 ?+R / Reload JS后就會看到頁面上顯示出 Title 下面跟著 2015. 注意,我們的圖片組件并沒有加載。這是因為我們還沒有指定裝載圖片的容器的大小了。 這個是通過 styles組件來完成了。現在我們可以來試著改寫我們需要的 style了,對于那些不要的樣式我們也可以直接去掉。
    var styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
      },
      thumbnail: {
        width: 53,
        height: 81,
      },
    });

    最后我們需要把這個樣式表賦值給圖象組件:


    <Image source={{uri: movie.posters.thumbnail}} style={styles.thumbnail} />

    再次點按?+R / Reload JS 后會發現圖片組件被成功加載了。


    加入一些樣式


    太棒了,現在就讓我們來美化一下我們的數據吧。讓頁面顯示的更好看點。 我打算將文本文件放在圖片的右邊,然后讓標題顯示的更大一點,并且居中顯示:
    +---------------------------------+
    |+-------++----------------------+|
    ||       ||        Title         ||
    || Image ||                      ||
    ||       ||        Year          ||
    |+-------++----------------------+|
    +---------------------------------+

    我們需要添加另外一個容器以便于能夠在這個水平排列的組件中加入一個垂直排列的組件。


    return ( <View style={styles.container}> <Image source={{uri: movie.posters.thumbnail}} style={styles.thumbnail} /> <View style={styles.rightContainer}> <Text style={styles.title}>{movie.title}</Text> <Text style={styles.year}>{movie.year}</Text> </View> </View> );


    并沒有改變太多,我們只是有文本文件周圍加了一個容器并且把他們移到了圖片的后面(因為我們計劃把文字排在圖片的右邊)。 讓我們看看樣式表最后是啥樣的:
     container: { flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', },

    我們的頁面布局使用的是 FlexBox, 可以在這個很棒的指導文件中了解更多相關的信息。

    在上面的代碼片段里面,我們也只添加了一行: flexDirection: ‘row’ 該條命令就能讓我們子容器里的內容采用是水平排列而不是默認的垂直排列。

    現在也把其他樣式表的信息加入 JS style 對象中:

     rightContainer: { flex: 1, },

     rightContainer 標簽里的命令信息表明該對象要占據的位置是在父容器中沒有被圖像所占據的位置空間了。 假如這個地方您沒有搞清楚,那就加一個 backgroundColor 到該樣式表中,然后試著把 flex: 1 去掉。 現在您就會注意到當前的容器剛剛好是能容納下子容器的大小了。

    樣式化文字的命令就非常直白了:
    title: { fontSize: 20, marginBottom: 8, textAlign: 'center', }, year: { textAlign: 'center', },

    繼續點按 ?+R / Reload JS,看看我們剛剛做的樣式是否都已經生效了。

    獲取真實的數據


    從那個爛西紅柿的 API 上面取回數據其實和我們學習 React Native并沒有直接的關系,所以如果在這一章節中您感覺有點跟不上的思路了也不用擔心。

    把下面所定義的常量都加入到文件的頂部(一般放于 requires 之下),創建一個 REQUEST_URL 用來去提取數據。
    /**
     * For quota reasons we replaced the Rotten Tomatoes' API with a sample data of
     * their very own API that lives in React Native's Github repo.
     */
    var REQUEST_URL = 'https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json';

    添加一些初始化的狀態到程序里面,以便于方便我們去檢查這樣的參數: this.state.movies === null,用來查看是否相關的電影數據已經被成功加載。 我們可以通過響應 this.setState({movies: moviesData})來設置這個數據。把這些代碼直接加到 React 類之上就可以了:
    getInitialState: function() { return { movies: null, }; },

    我們是希望在組件加載結束后立刻就發出索要數據的請求。  componentDidMount 是 React 組件的一個函數,在執行的過程中,React會在該組件成功加載以后調用該函數一次。
    componentDidMount: function() { this.fetchData(); },

    現在就可加 fetchData 功能了,這個是我們 app 的最主要的功能了。 該方法用來負責處理取回數據。 您所需要做的就是在執行過那一序列的操作之后調用 this.setState ({movies:data}),這一系列的操作包括React 工作,首先在 setState里面觸發再渲染的機制,然后是渲染功能,這時您就會看到 this.state.movies 已經不再是 null了。 我們在這個系列操作的最后調用 done() 方法 —— 一定要確認每次都調用了 done(), 不然的話,所有拋出來的錯都會被吞掉了。
     fetchData: function() { fetch(REQUEST_URL) .then((response) => response.json()) .then((responseData) => { this.setState({ movies: responseData.movies, }); }) .done(); },

    現在修改  render 方法以去潤色一個還沒有任何電影資料的加載視圖,還有潤色第一個電影數據。
    render: function() { if (!this.state.movies) { return this.renderLoadingView(); } var movie = this.state.movies[0]; return this.renderMovie(movie); }, renderLoadingView: function() { return ( <View style={styles.container}> <Text> Loading movies... </Text> </View> ); }, renderMovie: function(movie) { return ( <View style={styles.container}> <Image source={{uri: movie.posters.thumbnail}} style={styles.thumbnail} /> <View style={styles.rightContainer}> <Text style={styles.title}>{movie.title}</Text> <Text style={styles.year}>{movie.year}</Text> </View> </View> ); },

    重新點按 后,您應該能看到 Loading Movies字樣,直到我們去請求的數據返回來,然后程序就會開始展示從爛西紅柿網站取來的電影數據了。



    列表視圖


    現在我們就可以來修改 render 方法,把我們所有的數據都用列表視圖來展示, 這樣就不會每次只展示一條電影信息了。

    為什么這里選擇的是列表視圖,還不是把所有的信息都封裝好,然后放進滾輪視圖?盡管 React  已經夠快了,但是要讓他封裝一個有可能接受無限的列表元素不是會很慢。但是對于列表視圖來說,他每次只潤色那些夠一屏顯示的數據,那些沒有在當前屏展示的已經被潤色過的數據就會從原生視圖結構里面給去掉。

    最先做的事:添加列表視圖到文件的頂部去。
    var {
      AppRegistry,
      Image,
      ListView,
      StyleSheet,
      Text,
      View,
    } = React;

    現在,修改render 函數,以保證一旦我們拿到了數據就能給我們的電影潤色上去。
    render: function() { if (!this.state.loaded) { return this.renderLoadingView(); } return ( <ListView dataSource={this.state.dataSource} renderRow={this.renderMovie} style={styles.listView} /> ); },

    dataSource 是一個接口, ListView 可以根據這個接口來決定哪一行數據發生了變化,需要調用更新了。

    您也許注意到了,我們是從this.date里面調用 dataSource 文件。 下一步就是添加一個空的 dataSource 給對象,然后由 getInitialState 賦值后返回。 同時,我們也把數據存儲在了  dataSource 中,應該注意不要再使用  this.state.movies 了,以免存儲了數據兩次。 在這也要給狀態(this.state.loaded)一個布爾值以判斷拿取數據的過程是否結束。
     getInitialState: function() { return { dataSource: new ListView.DataSource({ rowHasChanged: (row1, row2) => row1 !== row2, }), loaded: false, }; },

    這里就是通過更新狀態修改后的 fetchData 方法:
     fetchData: function() { fetch(REQUEST_URL) .then((response) => response.json()) .then((responseData) => { this.setState({ dataSource: this.state.dataSource.cloneWithRows(responseData.movies), loaded: true, }); }) .done(); },

    最后讓我們給列表視圖添加好樣式代碼:
     listView: { paddingTop: 20, backgroundColor: '#F5FCFF', },

    您所應該看到最終效果應該是這樣的



    還有一些工作需要完成以完善這個app 的功能:比方添加導航,搜索,無限滾動加載等。 您可以查看 電影示例,看看這些功能是如何工作的

    附:全部代碼
    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     */
    'use strict';
    var React = require('react-native');
    var {
      AppRegistry,
      Image,
      ListView,
      StyleSheet,
      Text,
      View,
    } = React;
    var API_KEY = '7waqfqbprs7pajbz28mqf6vz';
    var API_URL = 'http://api.rottentomatoes.com/api/public/v1.0/lists/movies/in_theaters.json';
    var PAGE_SIZE = 25;
    var PARAMS = '?apikey=' + API_KEY + '&page_limit=' + PAGE_SIZE;
    var REQUEST_URL = API_URL + PARAMS;
    var AwesomeProject = React.createClass({
      getInitialState: function() {
        return {
          dataSource: new ListView.DataSource({
            rowHasChanged: (row1, row2) => row1 !== row2,
          }),
          loaded: false,
        };
      },
      componentDidMount: function() {
        this.fetchData();
      },
      fetchData: function() {
        fetch(REQUEST_URL)
          .then((response) => response.json())
          .then((responseData) => {
            this.setState({
              dataSource: this.state.dataSource.cloneWithRows(responseData.movies),
              loaded: true,
            });
          })
          .done();
      },
      render: function() {
        if (!this.state.loaded) {
          return this.renderLoadingView();
        }
        return (
          <ListView
            dataSource={this.state.dataSource}
            renderRow={this.renderMovie}
            style={styles.listView}
          />
        );
      },
      renderLoadingView: function() {
        return (
          <View style={styles.container}>
            <Text>
              Loading movies...
            </Text>
          </View>
        );
      },
      renderMovie: function(movie) {
        return (
          <View style={styles.container}>
            <Image
              source={{uri: movie.posters.thumbnail}}
              style={styles.thumbnail}
            />
            <View style={styles.rightContainer}>
              <Text style={styles.title}>{movie.title}</Text>
              <Text style={styles.year}>{movie.year}</Text>
            </View>
          </View>
        );
      },
    });
    var styles = StyleSheet.create({
      container: {
        flex: 1,
        flexDirection: 'row',
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
      },
      rightContainer: {
        flex: 1,
      },
      title: {
        fontSize: 20,
        marginBottom: 8,
        textAlign: 'center',
      },
      year: {
        textAlign: 'center',
      },
      thumbnail: {
        width: 53,
        height: 81,
      },
      listView: {
        paddingTop: 20,
        backgroundColor: '#F5FCFF',
      },
    });
    AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);

    不深思則不能造于道。不深思而得者,其得易失。

    名人名言- 曾國藩
    • By 優聯實達
    • 2015-10-26
    • 1464
    • 公司新聞,網站開發,網站設計,UI
  • 少妇高潮久久久久7777