如何加速 React.js 開發 — 我們遇到的三個問題與解決方案
ReactJS 是我們團隊內開發網頁時使用的函式庫,它提供了宣告式的 API 並讓網頁開發可以組件化,讓網頁的開發能夠夠容易規模化,除此之外, React 擁有活躍的生態系,大部分你遇過的問題,你需要的工具,都能在社群中找到。
在這篇文章中,我將會分享在團隊我們使用的技術,以及它解決了我們什麼問題。
1. Javascript 弱型別的特性讓程式碼容易有型別的錯誤,而且難以重構
0 == []
// True
這是一個 Javascript 弱型別的例子,寬鬆的型別檢查可以讓開發更快速嗎?一開始可以,但隨著程式碼變得複雜,Debug 難度會隨之提高。
同時,在需要重構部分程式碼的時候,因為不確定資料型別,需要更多時間去了解程式的上下脈絡,才能有自信的重構。
如果在不知道資料型別時重構,那就是在睜一隻眼閉一隻眼,自己騙自己。
我們採用 Typescript 作為型別檢查的解決方案
他能夠加速開發嗎?一開始可能與上方的敘述相反,當你一開始寫 Typescript 時,你會覺得慢了許多,因為你必須要定義 typing,然而些努力都會在 codebase 成長後得到回報,你會感謝從前的你(或你的同事)的努力,然後在往後的專案,你都會覺得必須要使用 Typescript。
Typescript 除了能夠透過語法就能檢查出型別的錯誤,還有一個巨大的優點, IntelliSense & autocomplete。如果你使用 VScode,Typescript 能夠提供可用的變數、屬性或者 module 的提示,這能夠大大加速開發時間,讓開發者可以專注在架構跟商業邏輯的實現,而不是在想變數的英文字母有沒有拼錯。
2. 需要 lint 保持程式碼風格一致,但要一一處理 warning 很麻煩
在團隊合作開發軟體時,保持程式碼風格一致很重要,如果能有一致的程式碼風格,會讓程式碼更加容易理解,並且在開發時能專注在程式邏輯,而非程式碼的語法差異。
Lint 是檢查程式碼風格的工具,讓團隊可以設置偏好的規則,然後透過 Lint 檢查。因爲我們使用 Typescript ,所以我們採用了 TSLint ,但要注意的是 TSLint 即將停止開發,因為 ESLint 將會支援 Typescript,如果要初步引進 Lint,可以考慮直接使用 ESLint。
使用 Lint 的好處顯而易見,但缺點也是。針對於無法自動修正的錯誤,開發者必須一一找到錯誤的地方並且手動修正,這個過程耗時且讓人感到挫折。後來我們發現,不只我們有這個困擾。
1. Open your ESLint config
2. Disable all styling rules (or add eslint-config-prettier which does that)
3. Install Prettier You’ll thank me.
Linters are there to help you find mistakes in your code. Not to torture you.
於是我們考慮使用 prettier
prettiier 是一個程式碼格式化工具。
程式碼的格式化與 lint 的最大差異在於,前者以產出一樣的風格為目標,後者以檢查特定的規則為目標。而這兩個工具可以同時使用,用 prettier 產出固定風格的程式碼,然後如果有額外必須要遵守的規則,就讓 Lint 提醒我們吧。
如此一來,大大減少了手動修正 lint 錯誤的工作量,也提供了一致的程式碼風格。
最後,我們還希望能夠自動執行 prettier,我們利用了 lint-staged 和 husky ,讓我們每次 commit 時都會先格式化程式碼,確保 codebase 中所有的程式碼都是格式化過的。
如果你對設置的過程以及我們的使用的參數有興趣,可以參考:
3. 使用 React 開發 component 時,lifecycle 中的邏輯無法重複使用
render props 與 high order component 都可以解決這個問題,但在 React 16.8 正式發佈之後,這個問題已有了標準答案:採用 React hook。
Hook 是 React 16.8 中增加的新功能。它讓你不必寫 class 就能使用 state 以及其他 React 的功能。 -https://zh-hant.reactjs.org/docs/hooks-intro.html
我們在 component 的實作上,全面改用 functional component 與 hook
我們決定全面採用 hook 和 functional component,因為 hook 讓開發者能夠使用簡潔的語法創造出可以重複使用的功能(functionality)。
同時我們不必重構舊有的 class component,官方並不建議我們重寫 class component,因為他們仍舊會繼續支援 class component。
如何使用 Hook 創造出可以重複使用的功能?
Hook 讓 reuse 功能變得可行的關鍵在於,Hook 將原先 class 提供的 lifecycle 和 state 功能,以更細緻的方式以 hook 拆分出來。例如:
在 class 中的功能實作:
若以 hook 實作變成:
從這個例子中可以看到,hook 將原先混雜在 lifecycle 中的邏輯,抽象化成兩獨立,自給自足的 hook,這讓功能的抽象化在 React 中變得更容易,可行了。
Hook 讓 React 開發者可以用更少的程式碼,創造更容易維護的 component,更容易規模化的應用程式。
最後,整理在這篇文章中我們遇到的問題與解決方案:
- 使用 Typescript 預防 javascript 的型別錯誤,讓重構程式碼更加容易,並且在開發時能夠讓編輯器提供 IntelliSense & autocomplete。
- 使用 prettier, tslint, lint-staged 和 husky 以自動格式化加上少部分的人工修改,確保 codebase 有一致的程式碼風格。
- 使用 React hook 以更少的程式碼,創造更容易維護的 component,更容易規模化的應用程式。