iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 30
4
Modern Web

在 React 生態圈內打滾的一年 feat. TypeScript系列 第 31

Day30 | Component 後, TypeScript 的定位在哪?

前言

這三十天內,我們學習了 React 及 TypeScript 的基本用法,最後一天想和大家聊聊,筆者是怎麼在專案中使用 TypeScript 的,或許有些人會認為 React + React-Redux + Redux-Saga 已經很完美了,為什麼最後還要硬加個 TypeScript,它真能幫助到我們開發嗎?

可以!

絕對是可以的,如同第一章所說的,筆者剛結束了 第二屆 F2E 精神時光屋 的切版活動,在活動的後期,筆者幾乎所有專案都上了 TypeScript,甚至到後期想偷懶簡單切版做功能的時候,沒有 TypeScript 還不曉得該怎麼開始,到底 TypeScript 有什麼魔力?就讓筆者以幾個作品來解釋。


React

利用 React 我們可以好好處理 View 的部分,包含資料的 Render,或是畫面類的邏輯(例如開關 Panel 等等),都可以用 React 的 Component 設計做到精細活化。

且我們使用了 React-Redux 管理 State,使得 View 上的資料能夠更乾淨,需要時再用 useState 提取就可以了,但是這麼做會有個問題,那就是我們全都把處理資料的邏輯都放到 Redux 上,那 Reducer 就會顯得特別擁擠,明明就只是在做 State 的處理而已,卻塞了一些處理資料的邏輯在裡面,會導致 Reducer 太過複雜,因為單一 Reducer 就會存放所有該資料的處理邏輯。

為了解決這個狀況,通常會將處理資料的邏輯給封裝起來,但是怎麼做呢?

Class 與 Interface 的物件導向

要封裝邏輯,使用 Class 便是一個很好的選擇,其實筆者使用 TypeScript 除了型別檢測外,最依賴的就是 Class 與 Interface 相輔相成,主要是透過 Interface 定義型別、Class 封裝邏輯,最後再將資料吐回 Reducer 之中更新 State,或是統一寫一個 function 讀出 Class 的 Property。

MP3 播放器 這個作品來說:

第一步先規劃出這個網站有哪些物件的呈現,而大家在學習熟悉 Class 時,也許會不曉得該怎麼統整 Class,這裡筆者有個小訣竅,從有資料的地方下手就對了,例如:播放器(含有播放、暫停、下一首、上一首等動作,當前播放列表等資訊)、播放列表(含有歌曲資訊)、歌曲(含有播放時間、歌名、圖片等等)這些東西就可以都做成 Class 操控。

關於播放器的 Class 可以先參考專案中的 src/lib/interface/IPlayer.ts,這是為播放器這個 Class 內容設計的 Interface,通常會先設計 Interface 再根據 Interface 撰寫 Class:

而實現此 Iplay 的 Class 在 src/lin/AudioPlayer.ts 之中,在裡面會封裝一些方法,例如上下一首歌或播放模式的切換:

將方法隔離開後,只需要在 Reducer 中創建 AudioPlayer 的實體後便能直接向播放器操作行為,最後再將 Class 中的資料更新 State 中。

src/reducer/player.ts:

在 line 21-20 先創建 AudioPlayer 的實體 player,之後定義 Reducer 管理什麼 State 的 Interface,而這些 State 都可以從 player 取出,因此操作邏輯的部分變成這樣子:

所有的動作幾乎都只是在呼叫 player 處理事情,處理完後再使用 updatePlayerInformationplayer 的資料取出來更新 State。

因此在這裡 Reducer 很優秀的做了邏輯與資料的橋樑,在 Reducer 中不會有 Action 的處理方式,這些事情被封裝隔離了,它所需做的只是執行然後更新資料,因此如果出現問題,不是 Redcuer 呼叫方法錯的話,那問題一定是在 Class 裡面。

測試

從測試角度來看,這樣子的職責分明也挺清楚的,透過 React 與 React-Redux 將「畫面」與「資料」分開,因此 React 只需要確認畫面上的東西有沒有正常 Render,與使用者的互動是否正常(點了按鈕後執行事件),Redux 只需要注意 Reducer 是否會根據 Action 處理資料,並正確更新 State。

加入 Class 後,Reducer 內的測試行為一樣,但是資料邏輯被我們拉到 Class 做處理,因此我們又將「資料」與「邏輯」分開來,測試的重心就放到了 Class 身上,基本上只要 Class 沒問題,Reducer 就不會有錯,除非是取了錯誤的資料。

其他案例

第一次使用後,筆者也不斷的嘗試此方法,因此也在 訂房系統線上聊天室雲端硬碟 都試著用上了,使用的方式也有稍微改變,解決一些語法上的缺點,當然還有許多技術債要處理,因為這幾個作品都在很短的時間內完成,所以沒有太多時間完善功能,包含撰寫測試案例。

如果有興趣的話也可以在專案上點個 star,預計在十月份過後,會開始整理作品,屆時會再將功能及測試補上。


結尾

在第一次使用此方式之前,筆者也思考過許多最佳實踐,最後覺得此寫法程式的可讀性最高,職責也非常清楚,希望如果有在使用 React 與 TypeScript 的大家,如果有認為 TypeScript 在設計方面有幫助到你們,也可以留言互相討論分享:)

最後感謝今年三十天來的陪伴,其實我不曉得文章內容與參賽的主題是否會讓人感到違和,但是這三十天的內容都是我在去年鐵人賽後到現在所學習到的一切,也想向大家傳達,

其實學習是永無止盡的,學會了技能後,能夠思考該怎麼使用,才是最重要的事情,

像孔子說的「學而不思則罔」對吧!不要放棄思考,然後去試著吸收前人的智慧及發掘自身的潛力,相信一年後,我也能夠帶著更新的姿態與大家見面:D

如果本系列的文章中有任何問題,或是不理解的地方,麻煩再留言告訴我!如果喜歡我的文章,也歡迎至 Medium 中按下訂閱,今後也會持續分享,謝謝大家!

神 Q 超人,再次下台一鞠躬!


上一篇
Day29 | 最強聯名款 TSX 上市-ESLint 篇
系列文
在 React 生態圈內打滾的一年 feat. TypeScript31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
1
暐翰
iT邦大師 1 級 ‧ 2019-10-11 18:13:04

恭喜完賽!
果然今年文章品質還是一樣優質 /images/emoticon/emoticon32.gif
今年再一起去夜市吧 /images/emoticon/emoticon37.gif

神Q超人 iT邦研究生 5 級 ‧ 2019-10-11 19:58:03 檢舉

夜市什麼的已經寫在我的行事曆上了 /images/emoticon/emoticon37.gif

1
石頭
iT邦高手 1 級 ‧ 2019-10-11 21:06:20

恭喜完賽!! 期待今年It邦幫忙頒獎典禮見面^^.

神Q超人 iT邦研究生 5 級 ‧ 2019-10-11 23:58:15 檢舉

一起完賽就是猛!今年如果得獎不會再讓 暐翰 一個人了 /images/emoticon/emoticon37.gif

1
Spark
iT邦新手 5 級 ‧ 2019-10-13 16:43:56

恭喜完賽!
在跑鐵人都沒時間看其他人的文~~
感謝分享欸,稍微翻了一下,這個系列質量好高啊~
剛好完賽後可以接著看!

神Q超人 iT邦研究生 5 級 ‧ 2019-10-13 18:55:47 檢舉

是你不嫌棄 ~ 你也剩下兩天而已!GOGOGO!
我也趁著結束的時候讀了ㄧ些沒時間看的主題,
和大神們學一下招/images/emoticon/emoticon01.gif

0
阿展展展
iT邦好手 1 級 ‧ 2019-10-29 04:47:22

恭喜完賽!!! /images/emoticon/emoticon64.gif

0
連城
iT邦新手 4 級 ‧ 2020-08-03 17:38:46

完賽拉~

感謝這篇帶著我一步一步完成
希望哪天我也可以參加鐵人賽
PS 我發現...原來我跟你同歲...

我要留言

立即登入留言