拆帳 app 和 React Native 初學心得
最近需要一個 app,方便和朋友出遊時拆帳。用 React Native 開發,過程滿順的。這篇記錄開發的過程。
寫好的 app 在這裡,下圖是它的使用流程:
- 點新增消費記錄。
- 輸入名稱、金額、由誰付帳、那些人需要付帳。
- 調整每個人的付費比例 (通常用預設值)。
- app 會自動計算每人應付已付的金額,有需要可以再作調整。確認無誤就按完成。
旅行結束後,在結算頁看每個人 多付/少付 多少錢。

開發流程
我會簡單的 JavaScript,會寫簡單的網頁;稍微會改 iOS/Android 程式,沒有從頭寫一個 app 的經驗。
學 React Native 時發現有幾個問題需要克服:
- ES6 (JavaScript 2015) 的語法
- React 的概念和 API
- React Native 的 API
- Android / iOS 的專案設定
但整體來說,對我這種不熟 Android / iOS 開發的人來說,用 React Native 寫基本功能還是方便不少。
ES6 語法
主要是讀 Babel 的 Learn ES2015,可以用它線上編輯器試語法。其它就隨便 google,以看 Mozilla 的文件為主,例如:arrow functions。
寫 React Native 的過程中,比較需要知道的是 arrow functions、let/const、template strings、modules (import),其它看看範例程式,照著寫沒什麼問題。
React / React Native
官網文件出乎意料地詳細,所以我就先跟著官網 tutorial 走一次,上面還有 live demo,很方便。若想快點嘗試開發,可以照著 Quick Start 作,不用裝 Xcode / Android Studio 就可以開發了,在手機上裝 Expo,然後程式載入到 Expo 裡執行。
不過我比較喜歡整個環境由自己控制,所以是照 “Building Projects with Native Code” 作一個獨立的 app。有需要試簡單的語法的話,用 Expo Snack 在網站上直接試 (這裡 Expo Snack 的介紹)。
看完官網 tutorial 後開始寫,寫一陣子覺得卡卡的,後來看了 Think in React有打通任督二脈的感覺。摘錄關鍵的幾句:
1. Is it passed in from a parent via props? If so, it probably isn’t state.
2. Does it remain unchanged over time? If so, it probably isn’t state.
3. Can you compute it based on any other state or props in your component? If so, it isn’t state.4. Identify every component that renders something based on that state.
Find a common owner component (a single component above all the components that need the state in the hierarchy).
5. Either the common owner or another component higher up in the hierarchy should own the state.
6. If you can’t find a component where it makes sense to own the state, create a new component simply for holding the state and add it somewhere in the hierarchy above the common owner component.
以常見個幾個例子來說:
- 若需要由 child 更新 parent 的 state,就由 parent 透過 props 傳 callback 給 child。
- siblings 透過 parent state 溝通 (e.g., 按下 button 處理 text input 內的文字)。
- parent 需要取得 child 的 state:看看能不能改成用 props 傳值和 callback 給 child 讀和寫值,不要存在 child 的 state 裡。真的得存在 child 身上的話,parent 傳 setter 給 child,透過 child 呼叫 setter 取得 child 的 state ( 例如 child 定義的 method)。
下面備忘幾份滿有幫助的文件,注意有些東西共通的東西要找 React 的文件。
- React.Component:了解 React 架構下,畫面更新的流程。
- JSX In Depth、Lists and Keys、Conditional Rendering:了解 React 寫 view 的各種方法。
- React Native Styling Cheat Sheet:沒看到官方有明確的詳表,但有各別的列表,像是 ViewStylePropTypes、TextStylePropTypes。
- 用 ref 取得 child object。
- Debug:用 alert(‘…’) 在畫面上跳出訊息框,或是用
console.log(),console.warn()然後用react-native log-android、react-native log-ios。遇到更複雜的情況,可以參考官方 Debug 文件。 - 寫 unit test 時如何 mock third-party module。
- Redux:看了 You Might Not Need Redux,想說先不用 Redux 寫看看。寫完還沒有需要用 Redux 的感覺,就沒有研究它了。等有更複雜的 case 時再看。
第三方套件
- React Navigation:這是滿新的東西,之前好像有各家 navigation 實作,今年四月以前關於 navigation 的文件都可以不用看了,改用這個就對了。Btw,這裡有提到用 StackNavigation 如何回到上上層的方法。文件不齊的地方,可以用文件裡的關鍵字回頭在程式碼裡搜尋,像是用 headerRight 找到 StackNavigation 的 navigationOptions 的完整參數。
- eslint:設定頗複雜的,沒找到特別滿意的設定。設好後記得要有 react/jsx-no-undef。我遇到最難找的 bug 是忘了 import module,用到 undefined component,然後 Android emulator 內的 app 就停住不動,也沒有 error log,過個一陣子 app 才 crash,實在是很雷。透過這個設定可以事先用 eslint 排除這類錯誤。
- 好用的免費 icon。
- prettier:懶得思考 ES6 + JSX 到底要怎麼縮排才對,那就跑 prettier 吧。
了解 JSX 語法和 React Navigation,基本上已可以應付我用到的流程。比較辛苦的是調整動畫,拿別人的套件來整,不太好同步不同套件之間的動畫。真的要作到好,可能要自己統一寫在一起吧。
Android / iOS 的專案設定
- 設定 Xcode 匯入 third-party 程式時 (Add files),記得點 options 選
Create groups for any added folders才會當作 source codes,被 Xcode 編譯。
雜談
我滿喜歡 React Native 以下幾點設計:
- 嚴格要求 unidirectional data flow,帶來的影響是容易重覆使用 component。重構也因此容易許多,看到重覆的程式,不費什麼力氣就能抽成一個新的 component。
- 將 template codes 直接寫在程式碼裡。
- 排版規則只有一套 flexbox,簡單易懂。
React Native 讓我第一次有動力完成一個 Android app,往後應該也會繼續用來寫小東西玩吧。
