IGNITE的官方地址:https://github.com/infinitered/ignite
IGNITE是一個React Native的腳手架生成器(了解ROR的可以理解為rails命令),通過一個命令就可以生成一個結(jié)構(gòu)完整的、可工作的空白react native項目,后續(xù)的開發(fā)就是向這個項目添磚加瓦,這比從頭構(gòu)建一個RN項目節(jié)省很多時間。而且IGNITE默認(rèn)集成的很多庫也都是不二之選,包含了前人的經(jīng)驗。本文解析一下ignite生成項目的結(jié)構(gòu)。
基本安裝和命令
使用ignite先要安裝:
- 安裝命令:npm install -g react-native-ignite
- 生成你的第一個項目,這需要一段時間:ignite new MyApplication
- 生成好的項目是可運(yùn)行的。進(jìn)入MyApplication目錄運(yùn)行以下命令就能看到成果了,如果這一步有問題,很可能是ios或者android原生編譯環(huán)境沒有設(shè)置好。
- react-native run-ios
- react-native run-android
- 如果沒跑起來,可以用npm start命令
開始幾步很簡單吧,除了react-native命令,其他都是npm命令,安裝的也大部分是js代碼,如果有問題,可以上網(wǎng)查查npm的基本用法。
除了生成腳手架項目,用ignite命令還能生成其他組件:
- 生成初始項目:ignite new MyApplication
- 添加組件:ignite generate component SmoothButton
- 添加容器:ignite generate container SubMenu
- 添加頁面:ignite generate screen Settings
- 添加listview:ignite generate listview HotDates
- 添加新的數(shù)據(jù):ignite generate redux Login
- 添加網(wǎng)絡(luò)請求:ignite generate saga Login
- 添加地圖控件:ignite generate mapview MapScreen
- 導(dǎo)入圖片資源:ignite import imagesfile
這些命令都很有用,可以先知道有哪些,具體用到時再看。
目錄結(jié)構(gòu)
項目目錄結(jié)構(gòu)和各部分的作用如下:
- App:ReactJS代碼,主要的業(yè)務(wù)邏輯都在這里,后面詳細(xì)說明。
- Tests:使用了AVA測試框架:https://github.com/avajs/ava,后面說明。
- android:android原生代碼。只有一個主application和一個主activity。這里的代碼只是用來把react啟動起來,沒有任何業(yè)務(wù)邏輯,初學(xué)可以忽略。
- ios:iOS原生代碼。跟android目錄一樣,有效代碼只有幾行,沒有任何業(yè)務(wù)邏輯,初學(xué)可以忽略。
- fastlane:https://github.com/fastlane/fastlane 支持ios/mac/android的自動發(fā)布工具
我們主要關(guān)注的是App目錄,其他部分等需要時再做了解。
采用的庫
項目集成了很多庫,下面列出所有庫的主要功能,主要也是為了備查,知道都是做什么用的,用到時再深入了解。
生產(chǎn)環(huán)境依賴庫:
- apisauce:js的JSON API客戶端。https://github.com/skellock/apisauce
- format-json:json格式化。https://github.com/johan/format-json
- lodash:下一代underline,擴(kuò)展js庫
- querystringify:URL輔助工具。https://github.com/unshiftio/querystringify
- ramda:函數(shù)式編程工具集。http://ramdajs.com/
- react
- react-native
- react-native-animatable
- react-native-config
- react-native-device-info
- react-native-drawer
- react-native-i18n
- react-native-maps
- react-native-router-flux:RN路由解釋器。用頁面(activity)名稱實現(xiàn)頁面間跳轉(zhuǎn)。https://github.com/aksonov/react-native-router-flux
- react-native-vector-icons:3000個字體圖標(biāo)。https://github.com/oblador/react-native-vector-icons
- react-redux
- redux
- redux-logger
- redux-persist:自動將redux持久化到AsyncStoragex中的工具。https://github.com/rt2zz/redux-persist
- redux-saga:redux異步處理工具
- reduxsauce:redux簡化庫,包含createActions, createReducer, createTypes等。
- seamless-immutable:不可變數(shù)據(jù)結(jié)構(gòu)。https://github.com/rtfeldman/seamless-immutable
生產(chǎn)環(huán)境依賴庫簡單總結(jié)。可以分為幾類:
- 輔助工具:format-json、lodash、querystirngify這些屬于輔助工具,是一些常用工具集。
- react類:react開頭的庫,都是處理view的。
- redux類:redux開頭的庫,都是處理數(shù)據(jù)的。特別是seamless-immutable、reduxsauce和redux-saga這3個庫串聯(lián)起來,可以方便的解決redux數(shù)據(jù)的云同步問題。可以參考這篇文章。
開發(fā)環(huán)境依賴庫:
- ava:js自動化測試工具。https://github.com/avajs/ava
- babel-eslint
- babel-preset-es2015
- enzyme:測試輔助工具集。https://github.com/airbnb/enzyme
- flow-bin:可以用命令執(zhí)行flow的工具。
- ghooks
- mockery:js的mock工具。
- nyc
- react-addons-test-utils
- react-dom
- react-native-mock
- reactotron-apisauce:reactotron是一個在控制臺上控制、監(jiān)控RN應(yīng)用的調(diào)試器。
- reactotron-react-native
- reactotron-redux
- reactotron-redux-saga
- snazzy
- standard-flow
除了下面的庫,還有兩個地方可以找到不錯的開發(fā)好的RN庫。一個是https://github.com/react-native-community/React-Native-Elements ,常用的界面元素都有。另一個是https://js.coach/react-native ,可以用來搜開發(fā)好的控件。例如微信支付模塊等。這個網(wǎng)站就是用react開發(fā)的。
React Native
介紹完周邊的依賴,現(xiàn)在開始進(jìn)入正題。
這個項目中真正的代碼都在App目錄下。App中的目錄結(jié)構(gòu)很清晰,叫什么名字放的就是什么東西。containers里都是容器,images里都是圖片,所以這里主要跟蹤運(yùn)行邏輯做介紹。
項目根目錄的兩個文件index.android.js和index.ios.js是不同平臺的入口文件,文件內(nèi)容完全一樣,都是調(diào)用App/Containers/App.js開始執(zhí)行。
App/Containers/App.js
RN程序的總?cè)肟凇K牡匚挥悬c類似android中的application。這里用<Provider store>來關(guān)聯(lián)redux store。App/Containers/RootContainer.js
根容器。所有的頁面都在這里顯示。這里用到了StatusBar和NavigationRouter。StatusBar是自帶的狀態(tài)欄控件,指手機(jī)屏幕最上邊顯示電池和時間那個條。可以控制它的背景色、透明度、是否顯示等。NavigationRouter是一個自定義的組件。-
App/Navigation/NavigationRouter.js
Router中描述了所有scene,每個scene是一個頁面(對應(yīng)android中的activity或者fragment)。最外層的drawer和drawerChildrenWrapper是一個抽屜結(jié)構(gòu)的菜單部分和頁面部分。drawer的菜單部分在NavigationDrawer中再介紹,這里只說頁面部分。可以看到頁面部分加載了很多style來定制外觀。內(nèi)部包含了若干個scene,其中第一個scene使用了initial關(guān)鍵字,表示這個頁面是第一個顯示的頁面。這里使用了react-native-router-flux的路由特性。每個頁面的key就是它的路由名字,component就是顯示時使用的組件。這些頁面還還可以定制標(biāo)題、導(dǎo)航條、導(dǎo)航條左功能和導(dǎo)航條右功能。
從這里可以看出,一個scene是一個頁面,但是頁面內(nèi)容本質(zhì)上是一個Component。為了理解方便,有時這個組件叫container,有時這個組件叫screen。可以用Scene的參數(shù)對它做小的定制。
- App/Navigation/NavigationDrawer.js
drawer為什么是個抽屜組件呢?因為這里用的就是<Drawer>,來自react-native-drawer庫。這里可以指定很多動作,例如打開、關(guān)閉時的動作。還有顯示哪些菜單,是用的一個新的組件。
content={<DrawerContent />}
- App/Containers/PresentationScreen.js
應(yīng)用打開時的首頁。這里都是view的代碼,使用了View/Image/ScrollView/Text等自帶控件,容易看懂。只有一個有趣的,是
<RoundedButton onPress={NavigationActions.componentExamples}>
Component Examples Screen
</RoundedButton>
它是一個自定義的圓角按鈕,定義不復(fù)雜。如果用android原生的9patch做這個按鈕,可是很麻煩。
- App/Containers/Styles/AllComponentsScreenStyle.js
展示了如何顯示只針對特定平臺的內(nèi)容。
if (Platform.OS === 'android') {
return (
<Text style={styles.sectionText}>
Android only: Animations are slow?
</Text>
)
}
App/Containers/Styles/UsageExamplesScreenStyle.js
這個頁面比較復(fù)雜,演示了登錄等內(nèi)容。先看render()中,都是普通代碼,主要交互代碼都在renderUsageExamples ()中。在這個函數(shù)中:根據(jù)登錄狀態(tài)顯示登錄、退出按鈕。這個狀態(tài)是放在this.props中的,結(jié)合其他代碼,能看出來,只有用戶交互的變量放在state中,來自網(wǎng)絡(luò)的變化都用的props。
登錄按鈕對應(yīng)的onPress動作是NavigationActions.login。愣了一下沒看到,后來看到這個NavigationActions就是react-native-router-flux的Actions才明白,這就是一次路由跳轉(zhuǎn)。跳轉(zhuǎn)去名為login的Scene,即loginScreen。
點擊下邊的小圖標(biāo)可以獲得溫度。獲取溫度的代碼在Services/Api.js中,在Sagas/index.js中重新綁定了。
后面有幾個頁面跳轉(zhuǎn)。
-
App/Containers/Styles/LoginScreenStyle.js
- 填寫用戶名和密碼,保存到state中。
- 在組件mount前和mount后,會監(jiān)聽虛擬鍵盤的狀態(tài),要調(diào)整顯示高度和寬度。用Metrics.screenHeight和Metrics.screenWidth獲取屏幕大小。這兩個應(yīng)該是像素數(shù)。
- 如果取消,就Actions.pop退出當(dāng)前頁。
- 如果確定,就調(diào)用LoginRedux和LoginSagas中的函數(shù)做登錄。登錄動作應(yīng)該是sagas的put做的,更改state,沒有實際的網(wǎng)絡(luò)請求。
這里redux、seamless-immutable、reduxsauce和redux-saga之間的關(guān)系還沒看明白。
App/Containers/APITestingScreen.js
請求json數(shù)據(jù)并顯示。App/Containers/ThemeScreen.js
多view顯示的一個示例。
總結(jié)
貌似到這view的部分也就差不多了。model相關(guān)的幾個關(guān)鍵庫的合作關(guān)系下次再寫。