React Native 簡介:用 JavaScript 搭建 iOS 應用 (1)

【編者按】本篇文章的作者是 Joyce Echessa——渥合數位服務創辦人,畢業于臺灣大學,近年來專注于協助客戶進行 App 軟體以及網站開發。本篇文章中,作者介紹通過 React Native 框架構建一個示例應用的開發過程,使得網絡技術和移動開發碰撞出絢麗火花,本文系 OneAPM 工程師編譯整理:

我們已經了解像 Titanium 和 PhoneGap 等框架,它們能讓開發者用 Web 技術構建移動應用。這是一個優勢,支持開發者使用原先網絡和移動開發的相關技術。不僅如此,相同的代碼庫經過小幅度的修改便能適用多個平臺——這就是著名的「一次編寫,到處運行」。然而,當涉及到構建應用的性能時,這些框架的缺點顯露無遺,盡管它們有一些吸引力,但卻一直更適用于構建原生應用。

React Native 簡介:用 JavaScript 搭建 iOS 應用
React Native 簡介:用 JavaScript 搭建 iOS 應用

React Native 卻與眾不同。像 PhoneGap 這樣的框架是將網頁內容包裝成 WebView,導致 UI 元素并沒有原生的感覺,而 React Native 則使用原生 iOS 或 Android 組件支持的 JavaScript 組件,所以你構建的應用是完全原生的。

Facebook 的湯姆 Occhino 在文章末尾鏈接視頻中說,React Native 并非是「一次編寫,到處運行」的框架。正如本教程所介紹,你使用特定平臺的組件來構造 UI,所以并不能直接將同樣的代碼放到 Android 上運行。React Native 是讓你學習這套技能,并可以用它在多種平臺上搭建應用,Occhino 更進一步闡明,這其實是「一次編寫,到處運行」的框架。在本文中,作者將介紹利用 React Native 框架構建一個簡單應用的完整開發過程。

開始吧!

首先,介紹一下在開發機器上安裝 React Native 的流程。

開始之前,應該提醒大家:你可以從 GitHub 獲取 React Native 框架代碼。接著運行其中的示例項目,比如2048(游戲)、Movies (電影瀏覽器應用)、SampleApp(空白的 React Native 應用)、TicTacToe (游戲)和 UIExplorer(這個應用展現了所有可能用到的 React Native 組件,比如 ListView、TabBar、MapView、Slider 等)。這些應用能幫助你學習使用 React Native 構建 UI 元素,尤其是 UIExplorer 應用程序,它提供了你可能需要用到的每個 UI 元素。但是,有些應用程序還有 Bug,筆者在嘗試運行時也出現過幾次崩潰。盡管如此,它們仍然非常值得學習,如需詳情,你可以了解下相關文檔

現在開始安裝。React native 利用 Node.js 來搭建 JavaScript 代碼。如果你電腦上已經安裝過,則可以跳過以下步驟,否則請繼續以下步驟。

我們選擇使用 Homebrew 來安裝 Node.js 框架。雖然這不是安裝 Node 的唯一方式,但我發現,Homebrew 是非常好用的包管理器。你可以用它很容易地安裝最新或特定版本的包、使用不同版本的軟件包、選擇要使用的版本、更新和卸載包等。想要安裝 Homebrew,可以直接去官網,按照網頁頁面頂部指令即可。由于鏈接可能會變,這里就不貼出下載鏈接了。

在 Homebrew 安裝好后,粘貼以下指令到終端窗口以安裝 Node.js。

brew install node

接著安裝 watchman。

brew install watchman

Watchman 是 Facebook 的文件監控器。React Native 用它來檢測代碼變化,以便重新編譯。

接著用下列指令安裝 React Native CLI 工具。

npm install -g react-native-cli

NPM 是 Node 的包管理器。你可以將它想象成 Ruby 中的 RubyGems、iOS 的 CocoaPods,以及 Java 中的 Gradle/Maven 等。它能夠讓你更容易地下載和管理項目所需的任何相關項。

在終端窗口,切換到你想要保存項目的文件夾,然后運行以下命令。

react-native init BookSearch

以上是用 CLI 工具來構建一個可以編譯和運行的 React Native 項目。當這個過程完成后,你會收到來自終端窗口的消息,在 Xcode 中打開 BookSearch.xcodeproj,并照常運行該應用程序。接下來模擬器將啟動你的應用,此外,將再打開一個終端窗口。當一個 React Native 應用啟動時,它將從以下網址加載 JavaScript 程序。

http://localhost:8081/index.ios.bundle

終端窗口打開后,會啟動 React Packager,并由服務器處理以上請求。React Packager 負責讀取并構建 JSX(之后會介紹)和 JavaScript 代碼。

React Native 簡介:用 JavaScript 搭建 iOS 應用
React Native 簡介:用 JavaScript 搭建 iOS 應用

運行應用時,你會看到下圖的模擬器。如果你要在設備上運行,應該按照以下幾個步驟。

React Native 簡介:用 JavaScript 搭建 iOS 應用
React Native 簡介:用 JavaScript 搭建 iOS 應用

順便說一句,你應該注意歡迎界面給出的關鍵指令:通過編輯創建項目時生成的 index.ios.js 文件,編輯應用的用戶界面,如果你修改了 JavaScript 代碼,用 Command-R 加載應用程序,看看有什么變化。如果你想要更多選擇,使用 Command-Control-Z 打開開發者功能表,它提供啟用時重新加載、瀏覽器調試等選項。

React Native 簡介:用 JavaScript 搭建 iOS 應用
React Native 簡介:用 JavaScript 搭建 iOS 應用

當你按照本文操作,模擬器上卻突然出現一個紅色屏幕時,不妨檢查一下模擬器上的錯誤消息。通過檢查可以排查出問題是出自代碼還是服務器。作者也曾經遇到幾次服務器連接失敗的情況,由模擬器反饋的錯誤消息是「無法連接到服務器」,然而檢查終端時得到「進程終止」的錯誤消息。面對這種情況時,需要關閉終端窗口,停止在 Xcode 上的應用,并重新運行。對于其他錯誤比如代碼中的語法錯誤、網絡請求超時錯誤(如果你的應用是從網絡獲取數據),在修正錯誤后再重新加載應該就可以了。

如果在鍵盤上按下 Command-R 沒什么用,那么鍵盤可能沒能連接到模擬器。從模擬器功能表中選擇硬件>鍵盤>連接硬件鍵盤,便能成功連接。

如果你已經完成以上步驟,卻仍沒有重新加載,那么可能需要重新啟動計算機。筆者曾經遇到過一次奇葩經歷,項目運行一切正常,但卻突然停止工作,重新啟動后又恢復正常。

現在開始構建我們的應用。打開 index.ios.js 文件。作者推薦使用適用于 Web 開發的 IDE。當然你也可以使用 Xcode,但不久你會發現它并不是很適合。當你需要代碼格式化時,它的用處不大,無法自動填充或語法錯誤高亮。對于適合的 JavaScriptIDE,你可以通讀本文后再做決定。我用的是 RubyMine,事實上只要是支持 JavaScript 的任何 IDE 都行,如果你選擇一個還能支持 JSX 的那會更好。

當打開 index.ios.js 文件時,你會發現這些代碼構建的是執行應用時所看到的 UI。

'use strict';

上述代碼開啟了 Strict Mode,這將為 React Native 中的 JavaScript 代碼加入了改良的錯誤處理能力。

var React = require('react-native');

上述代碼載入 react-native 模塊,并將其分配給 React 變量。在你可以調用模塊的所有功能之前,必須加載外部模塊到項目文件。就像在 Swift 和 Objective-C 中導入庫。

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

以上代碼被稱作解構賦值,能夠讓你分配多個對象屬性到一個單變量。使得這些屬性可以在整個文件范圍中引用。以上代碼是可選的,但如果你省略不要,那么每當你在代碼中使用一個組件時,你必須使用其完整名稱,例如「React.AppRegistry」、「React.StyleSheet」而不是 「AppRegistry」、「StyleSheet」。

var BookSearch = React.createClass({
  render: function() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <Text style={styles.instructions}>
          To get started, edit index.ios.js
        </Text>
        <Text style={styles.instructions}>
          Press Cmd+R to reload,{'\n'}
          Cmd+Control+Z for dev menu
        </Text>
      </View>
    );
  }
});

上面代碼創建了只有單一函數 render()的類。無論 render 中定義了什么,都將被輸出到屏幕。上述代碼使用 JSX(JavaScript 語法擴展)來構建應用的用戶界面。如果你之前已經使用 XML(甚至 HTML),那么對 JSX 應該不陌生。它同樣需要使用開始、結束標記,在標記中使用屬性來設置數值。React Native 不必非得使用 JSX,你可以用普通的 JavaScript,但筆者更推薦 JSX,因為它簡化了定義的樹結構的過程。如果你需要大量的代碼構建 UI,通過龐大的 JSX 樹結構使代碼可讀性更強。

var 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,
  },
});

以上代碼是應用于視圖內容的樣式。如果你以前做過網絡開發,而且使用過 CSS(層疊樣式表),那么這應該很熟悉。React Native 使用 CSS 設定應用的用戶界面。再看一眼 JSX 代碼,你會發現每個樣式都各有用途,例如 style={} styles.container 為容器定義樣式,容器是用來容納其他 UI 組件的外部視圖。

AppRegistry.registerComponent('BookSearch', () => BookSearch);

上行代碼定義了應用的入口。也就是 JavaScript 代碼開始執行的地方。

這是 React Native 用戶界面的基礎結構。每個定義的視圖將會遵循這一基礎結構。

在本篇文章中,我們將創建一個示例應用,可以瀏覽書籍,并看到詳細信息比如作者、標題、該書簡介。你也可以在應用中搜索書名和作者。下圖是該應用的成品圖,數據用的是 Google 書籍 API。

React Native 簡介:用 JavaScript 搭建 iOS 應用
React Native 簡介:用 JavaScript 搭建 iOS 應用

添加標簽欄

示例應用將有兩個項目的標簽欄——精選和搜索。我們首先添加該功能。

雖然你可以在 index.ios.js 中編寫所有代碼,但這種做法并不推薦,隨著應用代碼量的增加,整個框架容易變得混亂不堪。為了更便于管理,我們在不同的文件中創建類。

在項目中根目錄中創建兩個 JavaScript 文件(與 index.ios.js 文件在相同位置)。命名這兩個文件為 Search.js 和 Featured.js。打開 Featured.js 并添加以下代碼。

'use strict';
 
var React = require('react-native');
 
var {
    StyleSheet,
    View,
    Text,
    Component
   } = React;
 
var styles = StyleSheet.create({
    description: {
        fontSize: 20,
        backgroundColor: 'white'
    },
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center'
    }
});
 
class Featured extends Component {
    render() {
        return (
       <View style={styles.container}>
        <Text style={styles.description}>
           Featured Tab
        </Text>
    </View>
        );
    }
}
 
module.exports = Featured;

這段代碼你應該非常熟悉,非常類似于我們前面的代碼。我們設置 Strict Mode、加載 react-native 模塊、創建視圖樣式并用 render()函數渲染輸出到用戶界面。代碼的最后一行輸出精選類,從而使其可用于其他文件。請注意,我們聲明類和函數的方式,略微不同于示例 inindex.ios.js 文件。JavaScript 有不同的聲明類和函數的方式。隨意選擇你喜歡的風格。本篇文章接下來,我們將一直沿用上面所使用的樣式。

在樣式表定義中,我們可以看到基本的 CSS 屬性。我們為外部視圖中的文本和中心內容,設置字體大小和背景顏色。但你可能不熟悉 flex: 1 這行,這是最近才增加到 CSS 規范中的 flexbox。這里的 flex: 1 使得標記為容器的元素只占用的屏幕中的剩余空間,也就是只占用適應其內容的足夠空間。之后我們會進一步介紹 Flex。要了解更多關于 Flexbox 樣式,你可以參考這個指南。

在 Search.js 中添加下面代碼。

'use strict';
 
var React = require('react-native');
 
var {
    StyleSheet,
    View,
    Text,
    Component
   } = React;
 
var styles = StyleSheet.create({
    description: {
        fontSize: 20,
        backgroundColor: 'white'
    },
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center'
    }
});
 
class Search extends Component {
    render() {
        return (
        <View style={styles.container}>
            <Text style={styles.description}>
              Search Tab
            </Text>
        </View>
        );
    }
}
 
module.exports = Search;

上面的代碼與 Featured.js 的代碼很像,除了文本控件中的文字。

刪除 index.ios.js 中的所有內容,將下面的代碼粘貼進去。

'use strict';
 
var React = require('react-native');
var Featured = require('./Featured');
var Search = require('./Search');
 
var {
    AppRegistry,
    TabBarIOS,
    Component
   } = React;
 
class BookSearch extends Component {
 
    constructor(props) {
        super(props);
        this.state = {
            selectedTab: 'featured'
        };
    }
 
    render() {
        return (
            <TabBarIOS selectedTab={this.state.selectedTab}>
                <TabBarIOS.Item
                    selected={this.state.selectedTab === 'featured'}
                    icon={{uri:'featured'}}
                    onPress={() => {
                        this.setState({
                            selectedTab: 'featured'
                        });
                    }}>
                    <Featured/>
                </TabBarIOS.Item>
                <TabBarIOS.Item
                    selected={this.state.selectedTab === 'search'}
                    icon={{uri:'search'}}
                    onPress={() => {
                        this.setState({
                            selectedTab: 'search'
                        });
                    }}>
                    <Search/>
                </TabBarIOS.Item>
            </TabBarIOS>
        );
    }
}
 
AppRegistry.registerComponent('BookSearch', () => BookSearch);

此時,我們需要之前創建文件中導出的兩個模塊,并將它們分配給變量。在類中,我們指定一個構造函數,用來設置類的狀態。所使用的組件均有狀態變量,然后創建一個名為 selectedTab 的屬性,并將其值賦給「featured」。我們將利用「featured」來確定選項卡是否有效。最后為 Featured 標簽設定默認值。(未完待續...)

敬請持續關注:《React Native 簡介:用 JavaScript 搭建 iOS 應用》系列(2)(3).

原文地址:http://www.appcoda.com/react-native-introduction/

OneAPM 是應用性能管理領域的新興領軍企業,能幫助企業用戶和開發者輕松實現:緩慢的程序代碼和 SQL 語句的實時抓取。想閱讀更多技術文章,請訪問 OneAPM 官方博客

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,577評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,486評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,852評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,600評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,944評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,108評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,652評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,385評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,616評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,798評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,205評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,537評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,334評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,570評論 2 379

推薦閱讀更多精彩內容