Hooks 是 React 16.8 的新增特性。它可以讓你在不編寫 class 的情況下使用 state 以及其他的 React 特性。
使用 React hooks 轉化 class 的一些思考
Hooks 其實已經是大勢所趨的一個技術了,作為一個可能是 React,甚至是 JS 史上都是一個比較偉大的發明,Hooks 已經被大部分中小型公司所接受並嘗試使用,但是對於大中型公司來講,從 class 組件移植 Hooks 的成本太高,不能像其他公司一樣隨心所欲地擁抱新技術,所以我們對於 Hooks 的討論,應該考慮的比較全面,才能更好的了解這個技術,以及是否應該在項目中嘗試這一新技術。
在論壇上我也有和一個小伙伴對此有一個討論,感謝@無怨,前代 react 項目 class 轉 hooks 的必要性。其實大家對 hook 都是認可的,但是對於重寫 class 的成本方面還是望而卻步的,react 官方也不希望因為這個使得新版本使用者劇減,所以暫時還是會兼容 class 組件的寫法。
所以其實對於是重寫部分還是只有新組件使用 hook,大家都還是比較猶豫的,對這種選擇來看,我們必須實際考慮成本-產出比,所以我們這篇就具體討論成本與產出,以及可行的方案吧~
首先咱們來看看成本吧
修改成本
作為 React 16.8 新增特性,一些第三方的庫可能還暫時無法兼容 Hooks,比如 React Redux 從 v7.1.0 才開始支持 Hook API 並暴露了 useDispatch 和 useSelector 等,而 React Router 從 v5.1 開始支持 hooks。所以如果我們的項目中 Redux 和 Router 版本不夠的話,可能需要評價是否有必要升級和升級后可能帶來的問題。
再一點,業務邏輯內的代碼拆分。在 hooks 中,是不太建議將 state 放置於同一個 state 中的,考慮到性能及區域更新機制,既 state 切分成多個 state 變量,每個變量包含的不同值會在同時發生變化。建議是將 state 根據業務邏輯,拆分成多個 useState。
這樣雖然會增加組件的性能,畢竟每次更新都只是更新一部分組件,但是對於重寫 class,我們還需要深入每一個的 class,探究里面 state 的聯系、機制等等,是一個較大的阻礙與挑戰。
還有一點,暫時的話,hooks 必須傳遞 Props 的方式獲取根組件 App 中的 state,意思就是如果想使用主 reducer 庫中的 state 的話,必須使用 props 傳遞進來(或通過把 state 也裝進 Context 來解決,但是空間成本太大了),只有改變其值才可以 dispatch 來修改
修改成本可以算成本中最大的一環了,事實上每個 class 組件都可能有非常多的邏輯、狀態,各種狀態可能都有內在的一些聯系。重新去理解這部分代碼並重新構建 hooks,其實是一件非常大的挑戰,所以本身我暫時對重寫 class 到 hooks 是持觀望態度,當 React 官方沒有一定的苗頭出來說不支持 class 寫法前,重寫的動力確實是不夠充足。
學習成本
hook 本身其實和 class 一樣,都是關於本身這個組件的實現細節,重不重寫其實對書寫正常業務是完全沒有影響的(不考慮性能方面的話)。所以 hooks 對於 class 的重寫還是會有一定的學習成本在內,畢竟這邊要考慮本身與日后入職的小伙伴對這塊的熟練度。
時間成本
按我的預估,對一個完整項目中,class 組件轉 hooks,以及部分文件結構整理的時間可能要一個多月(以我的微薄水平),用戶看不見明顯的功能、UI 修改,不得不說這部分的時間支出是比較大的。
而如果是原 class 保留不動,新組件使用 hooks 的話,時間成本其實就減少很多了,畢竟新的組件也是從無到有搭建起來,多花的時間可能基本集中在前期對新增 hooks 的結構整理,以及對 redux 倉庫的有機結合上,當結構完善,有咱們自己的一套書寫模式之后,就可以達到現在書寫 class 組件的速度與體驗了。
我們能夠得到什么?
OK 我們說完了成本,來看看 Hooks 可以帶給我們什么?
假設是原 class 組件保留,新建 hooks
hooks 是一個 React 官方的新特性,Hook 的使用是完全能代替 class 組件的使用,也肯定對其有一個比較大的意義在其中,事實上他們內部原理都是 diff and patch,性能方面差距幾乎是可以忽略不計的,但是我的理解是,hooks 更傾向於函數式編程,class 則更傾向於面向對象編程。這是一個大趨勢。
在新的組件中使用 hooks,其實寫過之后就能體會到為什么有人說Hooks更騷,class更蠢
了。它將所有類似生命周期函數都可以用一個 useEffect 來進行模擬,不會使得自己的邏輯大量分布在 class 的各個角落,大幅度集成業務邏輯代碼。
這是新技術。對沒錯,我認為新技術本身就是一個我們能夠看到的"獲得"。在以前我們也會覺得 Jquery 非常好用,以后都會使用這種方式開發,但是后來出現了 webpack,出現了 React、Vue,我們的代碼書寫形式又變了。新技術的出現本身就是一種信號,只要它接受住了大量業務情況的考驗,他的存在就是有某種值得值得去獲取的優點,比如后來的組件化、工程化、解耦合等概念。
假設是重寫 class 組件
除了上述優點外,其實就沒有過多的其他優點了,只是整個項目的文件結構會更緊湊,畢竟不用兼容 class 寫法與 hooks 寫法,但是對於性能來說,是沒有那種顯著提升的。
額外
性能方面的差距其實是幾乎可以忽略不計的,但是函數式編程是越來越火起來的思想,同時 Hooks 從誕生開始就一直在致力於增強其性能,討論活躍度也足夠高,所以可預想的未來內,hooks 性能方面應該會有一個比較大的飛躍。所以這方面也應該是一個可參考的獲得。
方案
說了這么多,其實我們關於 hooks 的選擇就只有這三個:
-
重寫所有 class 組件,轉化為 hooks -
原 class 組件不懂,新組件使用 hooks -
原封不動,新組件依舊使用 class 開發
每個選擇都是有各自的考慮的,比如第一個選擇考慮的是成本較高,第三個選擇是想保持穩定以及開發時間。
建議假如是新項目或剛剛起步,就全篇使用 hooks 開發(第二種方案),如果已經是穩定上線的項目的迭代,就可以在迭代的組件中使用 hooks,但是如果你的團隊需要考慮學習時間成本,本身開發時間較緊張,那么還是建議依舊使用 class 組件進行接下來的開發,因為 class 已經很久了,你的團隊一定已經有了一套比較完備的方案與流程來進行接下來的開發,它會讓你節省不少的時間。
本文使用 mdnice 排版