從useEffect看React、Vue設(shè)計理念的不同
大家好,我卡頌。
我們知道,React發(fā)布Hooks后,帶來了業(yè)界一波Hooks熱。很多框架(比如Vue Composition API、Solid.js)都借鑒了Hooks的模式。
但是,即使這些框架都借鑒了Hooks,但由于框架作者的理念不同,發(fā)展方向也逐漸不同。
比如,在Vue Composition API中,對標(biāo)React useEffect API的是watchEffect,在Vue文檔中,有一小段內(nèi)容介紹他的用法:
而在React beta文檔中,介紹useEffect的,則有整整6節(jié)內(nèi)容:
為什么會有這樣的區(qū)別?讓我們從useEffect看看React、Vue設(shè)計理念的不同。
Vue與React的差異
當(dāng)Hooks剛問世時,他被看作是類組件的替代方案。文檔中介紹Hooks時也是將他與類組件對比。
其中useEffect的執(zhí)行時機(jī)囊括了如下3個生命周期函數(shù):
componentDidMount
componentDidUpdate
componentWillUnmount
反觀借鑒了Hooks的Vue Composition API,則同時提供了watchEffect API與不同場景的生命周期函數(shù)。
這里已經(jīng)體現(xiàn)出兩者設(shè)計理念的不同了:
React作為Facebook為探索「UI開發(fā)」最佳實踐而生的框架,一貫的做法是 —— 保持API穩(wěn)定(比如this.setState從React誕生伊始就一直存在)。
而Vue則借鑒了各種框架中的最佳實踐(比如虛擬DOM、響應(yīng)式更新...)。
所以,從易用性上來說,Vue Composition API是一定優(yōu)于React Hooks的,比如:
Hooks不能在條件語句中聲明
Hooks必須顯式指明依賴
并且,這種易用性的差異會隨著框架迭代,愈發(fā)明顯。
useEffect會越來越復(fù)雜
本著「保持API穩(wěn)定」的原則,當(dāng)前useEffect主要與上述三個生命周期函數(shù)相關(guān)。
但是,未來會有更多觸發(fā)時機(jī)與useEffect掛鉤。
所以,React團(tuán)隊在努力做一件事 —— 淡化useEffect與生命周期的關(guān)系,甚至淡化useEffect與組件的關(guān)系(因為當(dāng)談到組件時,很自然的會想到組件生命周期)。
怎么淡化呢?答案是 —— 在嚴(yán)格模式下,DEV環(huán)境會觸發(fā)多次useEffect回調(diào)。
如果你將useEffect當(dāng)作componentDidMount/WillUnmount來用,這個特性很可能讓你的代碼出bug。
React團(tuán)隊之所以這么做,就是想教育開發(fā)者 —— useEffect和生命周期沒有關(guān)系。開發(fā)者應(yīng)該將useEffect看作「針對某個數(shù)據(jù)源的同步過程」。
比如,下述聊天室組件,其中的useEffect可以看作是「針對聊天室連接的同步過程」:
const serverUrl = 'https://localhost:1234';
function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [roomId]);
// ...
}
當(dāng)聊天室組件mount、update、unmount時,對應(yīng)的同步過程應(yīng)該進(jìn)行。
當(dāng)roomId變化時,對應(yīng)的同步過程應(yīng)該進(jìn)行。
同理,如果React原生支持了Vue中的KeepAlive,那么當(dāng)聊天室組件從「可見」變?yōu)椤覆豢梢姟梗约皬摹覆豢梢姟棺優(yōu)椤缚梢姟範(fàn)顟B(tài),同步過程都應(yīng)該進(jìn)行。
所以,當(dāng)我們從「同步過程應(yīng)該何時進(jìn)行」的角度看待useEffect時,上述useEffect觸發(fā)時機(jī)都是合理的。
但是,如果從生命周期函數(shù)的角度看待useEffect,等未來(可能是v18的某個版本),Offscreen Component特性落地(對標(biāo)Vue中的KeepAlive),組件從「可見」變?yōu)椤覆豢梢姟範(fàn)顟B(tài)時,useEffect銷毀函數(shù)與useEffect回調(diào)函數(shù)會依次執(zhí)行,就會讓人很頭大。
這就是為什么,我上文說,React團(tuán)隊一直在淡化useEffect與生命周期的關(guān)系,甚至淡化useEffect與組件的關(guān)系。
一切都是為了「未來其他特性與useEffect的掛鉤」打下理論基礎(chǔ)。而這些特性從「組件」或「生命周期函數(shù)」的角度講不通。
這也是為什么在新文檔里有6節(jié)內(nèi)容與useEffect相關(guān)的原因。
作為對比,Vue在遇到新的場景時會怎么做呢?顯然是設(shè)計新的API。
總結(jié)
到底是提供一個API,但是能覆蓋更多場景(文檔有6節(jié)來介紹他)好,還是每個場景都提供一個API好?
不同開發(fā)者有自己的答案。
但有一點很明確,對于前端新手,React的上手難度會越來越高,而Vue的上手難度會盡可能保持平滑。
這里的前端新手,可能是想入行前端的新人,也可能是覺得「前端我也能干」的后端。
所以,對于當(dāng)前的從業(yè)者來說,這究竟是好事還是壞事呢?
作者:卡頌
歡迎關(guān)注微信公眾號 :魔術(shù)師卡頌