[0寫App基礎]第一個React Native App與CRNA(Expo)實作心得

Alex Shiu
Alex Shiu
Sep 3, 2018 · 12 min read

前陣子在實習其間首次開發React Native App,以CRNA(Create React Native App)配搭Expo實作。藉著這個機會來作個記錄和心得吧﹗嚴格來說,我以往沒有開發過app的經驗,甚至連java script也未寫過,所以可以說是由0開始的React Native App吧。

萬事起頭難,因此我將會分享如何可以有系統地,0寫app基礎的開始寫react native app。

將會用到的工具:
Expo
ignite CLI
NativeBase

作為新手,總會遇到以下的問題:架構怎麼擺,檔案怎麼放,網上找到的code應該放哪裡……因此,有一個好的模板的話,你會不用費心於架構,甚至可以大概預計到網上找的code應該放哪裡。因此,我以下將會用到一個叫做ignite CLI的模板去寫我的app。


首先先介紹一下Expo,Expo是一個工具幫你搞定了所有除了java script以外的問題。以最簡單來說,就是只要java script沒寫錯,app就能順利的build出來,不會遇到其他問題。另外,Expo 把統合了一堆實用的API,令你可以簡單的用到native modules或其他實用的東西, 比如說default camera, map, browser, etc。

當然使用expo也有缺點,目前我認為最大的缺點就是不能使用非純java script的library。如果要安裝的library不是純java script寫的話,就需要detach expo,即不再用expo寫你的project。那你要build app的時候就會變得有點麻煩。

然後要介紹的是ignite CLI。

ignite CLI 是一個模板,將你的project做好結構,分好了component, container(即是page), navigation, etc要放的位置,令你寫起來不用煩惱。同時,ignite CLI 也配備了一些plugin,例如用於處理不同國家語言的i18n,令你更方便。

Notes:
簡單來說,Components是會重用的UI組件,Containers是pages,Navigation是app的導航結構,Services是API,Themes是字型大小顏色格式類東西


安裝說明:
安裝時請一步一步確認沒有問題才進行下一步

首先要按指引用command裝了expo。
https://expo.io/learn
Expo官網這部分的指令好像寫錯了,expo create project 的指令應是這樣

exp init my-new-project
cd my-new-project
exp start 或 exp r

如果不想用command prompt的話,可以使用Expo XDE,Expo XDE 提供了介面去create project, open in device, publish, etc. 有興趣可以去看一看,不會在這裡詳說。

由於我是用android進行開發,所以可以用自己的手機或Genymotion Android Emulator進行測試。不論用了哪個方法甚麼,在連接好android手機後,可以用以下指令在android開啟app進行測試。我自己是用Genymotion的。

如果用了exp r這個指令去start的話,那一個command prompt將不可以運行exp android,我會開多一個comand prompt

cd my-new-project
exp android

完成後,之後就要裝ignite CLI了。
https://github.com/infinitered/ignite

npm install -g ignite-cli

由於我將會用expo進行開發,因此不能直接用ignite CLI的new指令create project,我會用一個經過修改,能在expo運行的ignite CLI: Ignite Expo Boilerplate。這個boilerplate需要先安裝ignite CLI 才能使用。使用以下指令create project with ignite CLI

https://github.com/jbosse/ignite-expo-boilerplate

ignite new MyLatestCreation -b ignite-expo

然後可以測試

cd MyLatestCreation
exp start 或 exp r

這時候可能會遇到error,如果遇到這個情況,就請按指引裝error要求的東西,比如說npm。如遇到這情況可以輸入以下指令。

npm install

如果沒問題,就可以進行測試。在手機開啟後,可能會遇到以下error

這個問題是由於expo sdkVersion 與 React Native Version不對所做成。Native version所用的0.52.0是對26.0.0的。
詳情請參考 https://docs.expo.io/versions/v26.0.0/sdk/

因此可以透過修改app.json解決。由原本的

"expo": {
...
"sdkVersion": "25.0.0",
...
}

改成

"expo": {
...
"sdkVersion": "26.0.0",
...
}

然後restart一次整個project,如果看到這個畫面就代表成功使用ignite CLI create project了。

現在,就可以開始快樂愉快地寫code了!


如果你想快速做好漂亮UI,推薦使用NativeBase這個套件。
NativeBase是一個套件提供一些已經做好的component給你使用,可以令你快速寫好漂亮的UI。

https://docs.nativebase.io/docs/GetStarted.html

請按指引按裝。

npm install native-base --save

注意,由於我使用Expo進行開發,因此要看Setup with CRNA

npm install @expo/vector-icons --save 

NativeBase 會用到一些custom字體,而這些字體需要在Visual component render前load完,所以要在Root Container加上以下的code。如何要用到Icon也是同理,需要先在render前load完。

async componentWillMount() {
await Expo.Font.loadAsync({
'Roboto': require('native-base/Fonts/Roboto.ttf'),
'Roboto_medium': require('native-base/Fonts/Roboto_medium.ttf'),
'Ionicons': require('native-base/Fonts/Ionicons.ttf'),
});
)
}

去到這裡,大家可以參考這篇看看react native component 的life cycle,看看componentWillMount這個function是做甚麼的。

由於要確保NativeBase用到的custom字體要load完才render,需要一個state去確保load完。所以整個class大概是這樣。

class RootContainer extends Component {
state={
isReady:false,
}

componentDidMount () {
this.props.startup()
}
async componentWillMount() {
await Expo.Font.loadAsync({
'Roboto': require('native-base/Fonts/Roboto.ttf'),
'Roboto_medium': require('native-base/Fonts/Roboto_medium.ttf'),
'Ionicons': require('native-base/Fonts/Ionicons.ttf'),
});
this.setState({isReady:true})
}
render () {
if (this.state.isReady) {
return (
<View style={styles.applicationView}>
<StatusBar barStyle='light-content'/>
<ReduxNavigation/>
</View>
)
}
else
return
<AppLoading/>
}
}

<AppLoading/> 是一個顯示空白的React component。


如果想簡單了解下React native 的基本概念,可以參下以下網址,雖然我不是用他的boilerplate。
https://noootown.gitbooks.io/deeperience-react-native-boilerplate/content/Introduction/React%20Native%20&%20Boilerplate.html

現在我簡單介紹一下Ignite Expo Boilerplate的運行次序

首先會從index.js開始,可是這個我不太清楚,所以本文將會忽略這部分。然後app.js會是index.js load完後要load的第一個component。然後會變成這樣:
app.js -> RootContainer.js(第一個visual component) -> ReduxNavigaion -> AppNavigation.js ->你的第一頁

因此我現在直接把前面的東西都忽略,直接看看AppNavigation.js

AppNavigation指的是app的導航,跳轉頁面的結構。寫React Native,通常navigation的部分都會用React Navigation。

PrimaryNav是一個stack,裡面define了可以push的container(page),以上圖為例,這個stack只能push LaunchScreen這個container。如果push了沒define的container進去,stack依然會是空的即使那個container已寫好。

initialRouteName寫的就是第一個會被push進stack的container。因此,上圖的app 第一個會顯示的page會是LaunchScreen.

如有更多對navigation的疑問,請在自行查找。

https://reactnavigation.org/

而page的文件就是放在container的資料夾裡。寫一個app最開始的部分莫過於UI,因此一開始最常開到的資料夾一定是Containers和Navigation。

每建立一個component或container,普遍來說都會有兩個檔案。

比如說,LaunchScreen就會有LaunchScreen.js 和LaunchScreenStyles.js 。

這個兩檔案。前者是container會用到的UI component,後者是container UI component的格式。

你以為ignite的功能只是幫你分好結構嗎?不只,當你需要開新的container, component, etc, 你都需要用到ignite,因為他會自動幫你將新加的東西放回boilerplate的結構。在project的directory輸入以下指令能看到教用教學。

ignite

簡單來說,最常用的莫過於

ignite new YourProjectName
ignite g container YourContainerName
ignite g component YourComponentName

假如我用了以上指令去generate一個新的container,contain.js和containerStyles.js也會自動建立並放到相應資料夾,同時於AppNavigation.js寫進stack。

現在,大家可以generate一個container ,開始試試自己的第一個頁面了!

當你generate一個新的container並運行於android,看到的畫面如果是這個就恭喜你,你成功了。


後記

心得去到這裡就差不多了。萬事起頭難,有手把手教學真的太好了﹗一旦開始了正式寫code的部分,就總有辦法寫下去,很多問題都可以找到要怎麼做。我很感歎如果可以省卻了這些初始的工作其實整件事會有趣很多。

要整理回這篇心得又花了幾天時間,因為我也忘記了某些步驟……有時記錄真的挺重要。

最後謝謝Playa大家的照顧和幫忙。

致和我一樣想開始又無從入手的新手。

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade