class已被淘汰,React 要推行函數式組件,心智模型更加“函數式”

class已經淘汰了?React 現在要推行函數式組件,你的觀點呢?

 

一些同學可能認爲“函數式組件+useState”不就是有狀態了嗎,不就是class組件的另一種寫法嗎?只不過更優雅一些?

我認爲fb團隊花那麼大的力氣,拽着整個React社區往一個前所未有的方向前進,原因肯定不僅僅是“寫法更優雅”。真正的原因如下:

1.hooks是比HOC和render props更優雅的邏輯複用方式。

這個是很多人喊“真香”的原因。優雅的邏輯複用方式,會促進一個更加蓬勃的生態,這對於原本生態就很強的react相當於如虎添翼。會有更多的人願意把自己的邏輯抽離成hooks(因爲真的太優雅了),發佈爲library,爲react生態添磚加瓦(看看這段時間各種基於hooks的狀態管理工具)。我還預測,很快會出現幾個“hooks圈子”的“lodash”。

class已經淘汰了?React 現在要推行函數式組件,你的觀點呢?

 

2.函數式組件的心智模型更加“聲明式”。

hooks(主要是useEffect)取代了生命週期的概念(減少API),讓開發者的代碼更加“聲明化”:

  • 舊的思維:“我在這個生命週期要檢查props.A和state.B(props和state),如果改變的話就觸發xxx副作用”。這種思維在後續修改邏輯的時候很容易漏掉檢查項,造成bug。
  • 新的思維:“我的組件有xxx這個副作用,這個副作用依賴的數據是props.A和state.B”。從過去的 命令式 轉變成了 聲明式 編程。
  • 其實仔細想一想,人們過去使用生命週期不就是爲了判斷是否要執行副作用嗎? 現在hooks直接給你一個聲明副作用的API,使得生命週期變成了一個“底層概念”,無需開發者考慮。開發者工作在更高的抽象層次上了。
  • 類似的道理,除了聲明副作用的API,react還提供了聲明“複雜計算”的API(useMemo),取代了過去“在生命週期做dirty檢查,將計算結果緩存在state裏”的做法。

class已經淘汰了?React 現在要推行函數式組件,你的觀點呢?

 

3. 函數式組件的心智模型更加“函數式”。

react團隊正在循序漸進地教育社區,爲未來的併發模式打下基礎。(其實react從一開始就受到了很多函數式編程的影響,現在推行函數式組件算是“迴歸初心”)。下面我會詳細討論函數式組件的心智模型。

函數式組件的心智模型

函數式組件絕不僅僅是“另一種寫法的class組件”,它和class的組件在心智模型還是存在很大差別的。 函數式組件依然是【外部數據=>view】的映射,依然是pure function的心智模型。 只不過現在外部數據不僅僅包括props和context,還包括state。

事實上,未來的併發模式就要求你使用pure function的心智模型來編寫函數式組件,否則很容易出bug。

class已經淘汰了?React 現在要推行函數式組件,你的觀點呢?

 

state是一種外部數據

有同學可能會問:“你在逗我吧?都useState了你還pure吶???”

但是你發現沒有,react對hooks的種種限制,不就是爲了讓你把useState等hooks 聲明 在函數組件的開頭?(當然,提高hooks的性能也是很重要的一個原因)並且,useState狀態聲明是 靜態聲明 ,不會因爲【props這種運行時因素】的變化而改變。你完全能寫個代碼分析工具,無需構建運行就能收集所有狀態聲明。

靜態聲明一個state,不就相當於用一個Wrapper組件來持有這個狀態,然後傳給它?那這個state不就可以理解爲一種外部輸入? 舉個例子:

// MyComp看起來好像有狀態,不是純函數 :( 
function MyComp() {
  const [state, setState] = useState(0)
  return <div>{state}</div>
}

相當於

// MyComp現在看起來更像一個純函數了吧!
function MyComp({state, setState}) {
  return <div>{state}</div>
}

function WrappedMyComp() {
  const [state, setState] = useState(0)
  return <MyComp state={state} setState={setState} />
}

後者看起來更像是在寫純函數了吧,但是兩者其實是等價的啊!那麼useState是不是就可以看作是一種語法糖,用來聲明它的Wrapper應該持有哪些狀態!只不過useState會自動幫你生成這些Wrapper。

這裏只是講心智模型,內部實現肯定會更加高效。

class已經淘汰了?React 現在要推行函數式組件,你的觀點呢?

 

事實上,hooks的前身,recompose 就提供了用來聲明狀態的HOC(`withState`),用它來包裹函數式組件以後,函數式組件就像自己擁有了state一樣。

綜上所述,useState得到的狀態可以理解爲一種外部傳入的狀態,就像props、context一樣。hooks時代的函數式組件依然是【外部數據=>view】的純函數。

這對於開啓併發模式是必備的條件。在併發模式下,react可以同時渲染“多個版本”的組件樹(比如,在渲染階段,一個優先級更高的事件發生了,要用這個事件改變的狀態進行新的渲染),對於某個版本,useState返回某個狀態值,對於另一個版本,useState返回不同的狀態值。react開發者只需要編寫純函數,不需要關心如何應對這些併發渲染。

而如果你用了class組件,就很容易出問題,因爲“多個版本”的組件樹,其中的class實例是共享的,你在某個組件樹中修改了this.A,其他組件樹能夠感知到。useRef也是同理,ref會造成組件樹之間相互影響,它是react團隊開的後門,建議謹慎使用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章