*React-Native基礎篇做者gitjavascript
*React-Native官方文檔html
*Demo前端
幾個月前facebook推出了React Native框架,容許開發着使用javascript代碼來實現iOS原生的應用,隨後十月份安卓版的也相繼問世,今後咱們能夠優雅的Learn once, write anywhere…java
早在幾年前開發者就開始使用javascript+html和PhoneGap來編寫各式各樣的app了,開發者能夠優雅的完成一套js的shell,而後分別在不一樣的平臺下進行打包,最終生成不一樣平臺的app,知識app的最終的展示形式都是html類型的。一度曾經出現webapp 是否要取代native ,這麼多年過去,結果你們也不言而知了。node
可是react native的確是一個很了不得的東西,開發者們都不由爲之歡呼,react native所展示出來的應用實質上是native應用,開發者完成同一套js代碼,分別在iOS和安卓平臺下分別打包最終分別能映射生成分屬不一樣的安卓原生應用與iOS原生應用,這個優點多是目前爲止被廣大開發最爲喜歡的地方,一直以來web app最爲你們所詬病的可能就是html的頁面永遠沒法與原生頁面的體驗相比擬。react
經過react native框架,你能夠用JavaScript來編寫和運行應用程序邏輯,而UI卻能夠是真正的本地代碼編寫的,所以,你徹底不須要一個HTML5編寫的UI。ios
React框架採用了一種新穎的、激進的和高度函數式的方式來構建UI。簡單說,應用程序的UI能夠簡單地用一個函數來表示應用程序當前的狀態git
React Native的重點是把React編程模型引進到移動App的開發中去。它的目的並非跨平臺,一次編寫處處運行。它真正的目標是「一次學習多處編寫」。這是一個重大的區別。本教程只涉及iOS,但一旦你學會了它的思想,你就能夠快速將一樣的知識應用到Android App的編寫上。github
React Native的編寫模式更加友好於從事於js的前端開發者,它自己採用了React js的模式,尤爲是從事React js的開發人員,只須要熟悉下基本的文檔就能瞬間變成一個iOS+安卓雙向通吃的移動專家,React內部引入可一些新的概念,如 DOM和reconciliation,React直接將函數式編程的理念用到了UI層面。
不過相對來講,OC的開發人員只要熟悉一下基本demo看上幾個例子應該就不會有太多問題了,若是以前有過web端開發經驗的話相信上手會更快一些。web
下面介紹一個簡單的demo操做,這個教程一塊兒帶你去體驗一下京東促銷砍啊砍頁面的OC->React 移植過程,經過本教程你就能夠了解React Native的一些基本開發流程了。
效果:
若是你以前從未寫過任何 JavaScript ,別擔憂;這篇教程帶着你一點一點編寫代碼。React 使用 CSS 屬性來定義樣式,這些樣式一般都很易於閱讀和理解,可是若是你想進一步瞭解,能夠參考:。
要想學習更多內容,請往下看
React native 關於環境搭建問題此處就很少說了,詳情請見React native基礎教程,此處就從咱們已經準備好一切前序工做開始,萬事具有隻欠東風,下面開始:
首先React Native 啓動畫面開始,建立helloworld工程,啓動畫面以下:
與此同時Xcode還會打開一個終端窗口,並顯示以下信息:
這是React Navtive Packager,它在node容器中運行。你待會就會發現它的用處。
千萬不要關閉這個窗口,讓它一直運行在後面。若是你意外關閉它,能夠在Xcode中先中止程序,再從新運行程序。
注意:
React Native完成的js完成的代碼實際上是跑在本地的node下面的,從appdelegate裏面能夠看到React Native工程會從一個本機地址「http://localhost:8081/index.ios.bundle?platform=ios&dev=true」讀取一個對應的文件,這個文件中就是系統已經自動幫你打包壓縮整合過之後的一個js 代碼庫,接下來React Native引擎會將這個庫中的js代碼徹底的解析、翻譯成對應的iOS原生內容,最終以iOS原生UI的形式渲染到桌面上,這個就是React Native整個工做流程。
在開始編寫這個demo以前咱們先建立一個簡單的Hello World項目,用你喜歡的文本編輯器(例如Sublime Text)打開index.ios.js ,刪除全部內容。而後加入如下語句:
'use strict'; var React = require('react-native'); var { AppRegistry, Text, View, } = React; var HelloWorld = React.createClass({ render: function() { return ( <View> <View><Text>你好, React Native</Text></View> </View> ); } }); AppRegistry.registerComponent('HelloWorld', () => HelloWorld);
好了,「Hello World」 的演示就到此爲止;接下來咱們要編寫一個真正的React App了!
這個demo使用了標準的UIKit中的導航控制器來提供」棧式導航體驗「。接下來咱們就來實現這個功能。
在 index.ios.js, 添加如下代碼:
var Home = require('./cut/Home'); var HelloWorld = React.createClass(//{ render: function() //{ return ( <NavigatorIOS initialRoute=//{//{title:'首頁', component:Home, //}//}//> ); //} //});
NavigatorIOS就是React Native中對應的導航視圖,咱們再次暫時能夠理解就是iOS中的UINavigationController,咱們在此處建立了一個基於導航的視圖控制器,rootViewController對應的頁面就是Home。
var cutList = require('./CutList'); var Home = React.createClass({ render:function (){ return ( <TouchableHighlight onPress={()=> this.goToNext()}> <View> <Text}>go to cut</Text> </View> </TouchableHighlight> ); }, goToNext:function(){ this.props.navigator.push({ component: cutList, }); }, });
Home 咱們只放了一個按鈕,按鈕文字「go to cut」,另外添加了一個點擊觸摸事件,事件相應題是goToNext:function(); 在函數處理事件內部,咱們只作了頁面的push跳轉,目標頁面是cutList頁面,運行效果以下:
輪播圖這個地方採用了React Native的一個第三方庫swiper(偷懶了),
var Swiper = require('react-native-swiper'); 初始化數據 var sliderImgs = [ 'http://m.360buyimg.com/mobile/s725x175_jfs/t2332/80/701506039/111191/37a1273/5624850bN2469d61f.jpg', 'http://m.360buyimg.com/mobile/s725x175_jfs/t2401/354/694665708/117887/3a283185/56248ee2N58518e76.jpg', 'http://m.360buyimg.com/mobile/s725x175_jfs/t2506/269/651438394/152836/cf430d42/561f6b3aN80cb83f4.jpg', 'http://m.360buyimg.com/mobilecms/s750x410_jfs/t2326/263/687562306/170970/c3f92c7/5620cbddNaa6a2cda.jpg!q70.jpg', 'http://m.360buyimg.com/mobilecms/s750x410_jfs/t1891/237/637408747/193879/1acee0f7/5620be19N801621e4.jpg!q70.jpg' ]; //初始化UI render:function () \\{ return ( <View> <View> <Swiper style=\\{styles.wrapper\\} showsButtons=\\{false\\} autoplay=\\{true\\} height=\\{150\\} showsPagination={true}> <Image style={[styles.slide,]} source=></Image> <Image style={[styles.slide,]} source=></Image> <Image style={[styles.slide,]} source=></Image> <Image style={[styles.slide,]} source=></Image> <Image style={[styles.slide,]} source=></Image> </Swiper> </View> <View style={styles.listViewSuper}> <ListView style={styles.tableStyle} dataSource = {this.state.dataSource} renderRow={this._renderRow.bind(this)} pageSize={5} automaticallyAdjustContentInsets={false}//> </View> </View> ); },
再次看到render:function()這個函數,應該沒那麼陌生了吧,暫時能夠理解render至關於ViewController中的ViewDidLoad:,咱們通常在render裏面作一些初始化UI視圖的工做,此處咱們初始化了swiper和ListView
swiper
ListView
getInitialState:function(){ var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); return { dataSource: new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 }), loaded:false, currentPage:0, }; }
getInitialState:function()相似於OC中的init函數,咱們通常的習慣喜歡在init函數初始化一個變量等數據,在React Native依舊是這樣。
//定義request url var urlPath = 'http://ccguo.gitcafe.io/cut.json'; var CACHE = []; //componentDidMount:function 系統方法 componentDidMount:function(){ this.fetchData(); }, //自定義函數處理網絡獲取數據,將數據放入全局變量CACHE cache:function(items){ for (var i in items) { CACHE.push(items[i]); } this.setState({ dataSource: this.state.dataSource.cloneWithRows(CACHE), }); }, //發起 網絡請求,得到json fetchData:function(){ console.log('hello world'); fetch(urlPath) .then((response) => response.json()) .then((responseText) => { console.log(responseText.cutList); this.cache(responseText.cutList); }) .catch((error) => { console.log(error); }); }
這個過程模擬了在iOS原生應用裏面,初始化網絡request,發起網絡請求,獲得數據,解析數據,而後將數據存入list這一些列操做,其實在js中,js腳本處理json的能力仍是很強的,咱們不再須要像OC中哪些objectForKey:的操做了,咱們不須要任何MJExtension、JSONModel、 Mantle等一些潛在的工具了,省去了不少的麻煩,咱們直接拿到一個json對象,直接對對象進行操做。
另外React的網絡請求此處咱們只是使用了fetch API
臉譜官方的api(臉譜對於網絡請求提供了多種API,如:fetch WebSocket XMLHttpRequest等,具體可參照API)
從代碼上看js的鏈式編程剛看上去有點不太習慣,不過總體使用起來仍是比OC中快捷多了,foreach遍歷、消息隊列進出棧,總之腳步裏面省去了以往還不得不在乎的好多麻煩,其實這塊相對swift而言,新的版本中漸漸的已經獲得了部分提高,不過仍是要感謝臉譜團隊,沒有他們,可能還見識不到React的強大。
_renderRow:function(data,sectionID,rowID){ return ( <TouchableHighlight onPress={() => this._pressRow(data,rowID)}> <View style=> <View style=> <View style=> <Image style= source=></Image> </View> <View style={styles.row,{flex:3,borderColor:'blue',borderWidth:0.5}}> <Text style=> {rowID+'-'+data.wname} </Text> <Text style=>京東價318.00</Text> <View style=> <Text style=>已有256人砍價</Text> <Text style=>立刻砍</Text> </View> </View> </View> <View style={styles.separator} /> </View> </TouchableHighlight> ); }, _pressRow: function(data,rowID) { this.props.navigator.push({ component: detail, passProps: {data: data} }); }
在上述初始化ListView UI的時間,咱們指定了renderRow 對應的action事件,此處咱們能夠直接在_renderRow:function中構建本身的cell模版,至於React Native中UI的標籤基本用法,你們能夠去頭部基礎教程裏面找,有點相似於html標籤,總之咱們在_renderRow:function純碎是構造cell的代碼,這個相似於tableViewCell subClass, cell點擊事件咱們使用一個TouchableHighlight來代替
<TouchableHighlight onPress={() => this._pressRow(data,rowID)}> .... </TouchableHighlight>
TouchableHighlight事件處理action一樣是一個函數(不解釋),在_pressRow事件中咱們處理本身的cell點擊跳轉,順便插一句下一步的操做,_pressRow(data,rowID)是帶有形參的
另外 ListView renderRow 事件的重載函數,形參類型這個具體參照臉譜官方的api
_renderRow:function(data,sectionID,rowID)。
總體運行效果以下:
var detail = require('./Detail'); _pressRow: function(data,rowID) { this.props.navigator.push({ component: detail, passProps: {data: data} }); }
React在處理事件跳轉的時間,仍舊採用進棧出棧的形式,這一點和Apple的理念仍是相似的。
<Text style={styles.view}>{this.props.data.wname}</Text>
到了目標頁面後,咱們直接從props容器直接根據key就能將傳遞的參數去處,此處咱們傳遞參數的自己是一個json,咱們只是講wname顯示到detail頁面。
效果以下:
恭喜你,你的第一個React Native App終於完成了!你能夠在GitHub上找到每個」可運行的「步驟的項目源文件,若是你搞不定的時候它們會很是有用的 :]
若是你來自Web領域,你可能以爲在代碼中用JS和React框架創建基於本地化UI的App的界面並實現導航不過是小菜一碟。但若是你主要開發的是本地App,我但願你能從中感覺到React Native的優勢:快速的App迭代,現代JavaScript語法的支持和清晰的CSS樣式規則。
在你的下一個App中,你是會使用這個框架,仍是會繼續頑固不化地使用Swift和O-C呢?
不管你怎麼選擇,我都但願你能從本文的介紹中學習到一些有趣的新東西,並把其中一些原理應用到你的下一個項目中。
若是你有任何問題及建議,請參與到下面的討論中來!