成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

React Hooks的丑陋一面

開發(fā) 前端
在這篇文章中,我將分享我對React Hooks的觀點(diǎn),正如這篇文章的標(biāo)題所暗示的那樣,我不是一個(gè)忠實(shí)的粉絲。

在這篇文章中,我將分享我對React Hooks的觀點(diǎn),正如這篇文章的標(biāo)題所暗示的那樣,我不是一個(gè)忠實(shí)的粉絲。

讓我們來分析一下React官方的文檔中描述的放棄類而使用鉤子的動(dòng)機(jī)。

[[342836]]

動(dòng)機(jī)1:class令人困惑

我們發(fā)現(xiàn),class可能是學(xué)習(xí)React的一大障礙,你必須了解 this 在JavaScript中的工作方式,這與大多數(shù)語言中的工作方式截然不同。你必須記住要綁定事件處理程序,代碼會(huì)非常啰嗦,React中函數(shù)和類組件之間的區(qū)別,以及何時(shí)使用每個(gè)組件,甚至在有經(jīng)驗(yàn)的React開發(fā)人員之間也會(huì)導(dǎo)致分歧。

好吧,我可以同意 this 在你剛開始使用Javascript的時(shí)候可能會(huì)有點(diǎn)混亂,但是箭頭函數(shù)解決了混亂,把一個(gè)已經(jīng)被Typescript開箱即用支持的第三階段功能稱為“不穩(wěn)定的語法建議”,這純粹是煽動(dòng)性的。React團(tuán)隊(duì)指的是class字段語法,該語法已經(jīng)被廣泛使用并且可能很快會(huì)得到正式支持:

  1. class Foo extends React.Component { 
  2.   onPress = () => { 
  3.     console.log(this.props.someProp); 
  4.   }  render() {    return <Button onPress={this.onPress} /> 
  5.   } 

如你所見,通過使用class字段箭頭函數(shù),你無需在構(gòu)造函數(shù)中綁定任何內(nèi)容,并且它始終指向正確的上下文。

如果Class令人困惑,那么對于新的鉤子函數(shù)我們能說些什么呢?鉤子函數(shù)不是常規(guī)函數(shù),因?yàn)樗哂袪顟B(tài),看起來很奇怪的 this(又名 useRef ),并且可以具有多個(gè)實(shí)例。但這絕對不是類,介于兩者之間,從現(xiàn)在開始,我將其稱為 Funclass。那么,對于人類和機(jī)器而言,那些Funclass會(huì)更容易嗎?我不確定機(jī)器,但我真的不認(rèn)為Funclass從概念上比類更容易理解。

類是一個(gè)眾所周知的思想概念,每個(gè)開發(fā)人員都熟悉 this 的概念,即使在javascript中也有所不同。另一方面,F(xiàn)unclass是一個(gè)新概念,一個(gè)很奇怪的概念。它們讓人感覺更神奇,而且它們過于依賴慣例而不是嚴(yán)格的語法。你必須遵循一些嚴(yán)格而奇怪的規(guī)則,你需要小心你的代碼放在哪里,而且有很多陷阱。還要準(zhǔn)備好一些可怕的命名,比如 useRef( this 的花哨名字)、useEffect、useMemo、useImperativeHandle(說什么呢?)等等。

類的語法是為了處理多實(shí)例的概念和實(shí)例范圍的概念(this 的確切目的)而專門發(fā)明的。Funclass只是一種實(shí)現(xiàn)相同目標(biāo)的奇怪方式,許多人將Funclass與函數(shù)式編程相混淆,但Funclass實(shí)際上只是變相的類。類是一個(gè)概念,而不是語法。

在React中,函數(shù)和類組件之間的區(qū)別,以及何時(shí)使用每一種組件,甚至在有經(jīng)驗(yàn)的React開發(fā)人員之間也會(huì)產(chǎn)生分歧。

到目前為止,這種區(qū)別非常明顯——如果需要狀態(tài)或生命周期方法,則使用類,否則,使用函數(shù)或類實(shí)際上并不重要。就我個(gè)人而言,我很喜歡這樣的想法:當(dāng)我偶然發(fā)現(xiàn)一個(gè)函數(shù)組件時(shí),我可以立即知道這是一個(gè)沒有狀態(tài)的“啞巴組件”。遺憾的是,隨著Funclasses的引入,情況不再是這樣了。

動(dòng)機(jī)2:很難在組件之間重用有狀態(tài)邏輯

具有諷刺意味嗎?至少在我看來,React最大的問題是它沒有提供一個(gè)開箱即用的狀態(tài)管理方案,讓我們對應(yīng)該如何填補(bǔ)這個(gè)空白的問題爭論了很久,也為Redux等一些非常糟糕的設(shè)計(jì)模式打開了一扇門。所以在經(jīng)歷了多年的挫折之后,React團(tuán)隊(duì)終于得出了一個(gè)結(jié)論:組件之間很難共享有狀態(tài)邏輯......誰能想到呢?

無論如何,勾子會(huì)使情況變得更好嗎?答案是不盡然。鉤子不能和類一起工作,所以如果你的代碼庫已經(jīng)用類來編寫,你還是需要另一種方式來共享有狀態(tài)的邏輯。另外,鉤子只解決了每個(gè)實(shí)例邏輯共享的問題,但如果你想在多個(gè)實(shí)例之間共享狀態(tài),你仍然需要使用stores和第三方狀態(tài)管理解決方案,正如我所說,如果你已經(jīng)使用它們,你并不真正需要鉤子。

所以,與其只是治標(biāo)不治本,或許React是時(shí)候行動(dòng)起來,實(shí)現(xiàn)一個(gè)合適的狀態(tài)管理工具,同時(shí)管理全局狀態(tài)(stores)和本地狀態(tài)(每個(gè)實(shí)例),從而徹底扼殺這個(gè)漏洞。

動(dòng)機(jī)3:復(fù)雜的組件變得難以理解

如果你已經(jīng)在使用stores,這種說法幾乎沒有意義,讓我們看看為什么。

  1. class Foo extends React.Component { 
  2.   componentDidMount() { 
  3.     doA();  
  4.     doB();  
  5.     doC(); 
  6.   } 

在這個(gè)例子中,你可以看到,我們可能在 componentDidMount 中混合了不相關(guān)的邏輯,但這是否會(huì)使我們的組件膨脹?不完全是。整個(gè)實(shí)現(xiàn)位于類之外,而狀態(tài)位于store中,沒有store 所有狀態(tài)邏輯都必須在類內(nèi)部實(shí)現(xiàn),而該類確實(shí)會(huì)臃腫。但看起來React又解決了一個(gè)問題,這個(gè)問題大多存在于一個(gè)沒有狀態(tài)管理工具的世界里。實(shí)際上,大多數(shù)大型應(yīng)用程序已經(jīng)在使用狀態(tài)管理工具,并且該問題已得到緩解。另外,在大多數(shù)情況下,我們也許可以將這個(gè)類分解成更小的組件,并將每個(gè) doSomething() 放在子組件的 componentDidMount 中。

使用Funclass,我們可以編寫如下代碼:

  1. function Foo() { 
  2.   useA();  
  3.   useB();  
  4.   useC(); 

看起來有點(diǎn)干凈,但是是嗎?我們還需要在某個(gè)地方寫3個(gè)不同的useEffect鉤子,所以最后我們要寫更多的代碼,看看我們在這里做了什么——有了類組件,你可以一目了然地知道組件在mount上做什么。在Funclass的例子中,你需要按照鉤子并嘗試搜索帶有空依賴項(xiàng)數(shù)組的 useEffect,以了解組件在mount上做什么。生命周期方法的聲明性本質(zhì)上是一件好事,我發(fā)現(xiàn)研究Funclasss的流程要困難得多。我見過很多案例是Funclasses讓開發(fā)者更容易寫出糟糕的代碼,我們后面會(huì)看到一個(gè)例子。

但是首先,我必須承認(rèn) useEffect 有一些好處,請看以下示例:

  1. useEffect(() => { 
  2.   subscribeToA();  return () => { 
  3.     unsubscribeFromA();  }; }, []); 

useEffect 鉤子讓我們將訂閱和退訂邏輯配對在一起。這其實(shí)是一個(gè)非常整潔的模式,同樣的,把 componentDidMount 和 componentDidUpdate 配對在一起也是如此。以我的經(jīng)驗(yàn),這些情況并不常見,但它們?nèi)匀皇怯行У挠美谶@里 useEffect 確實(shí)很有用。問題是,為什么我們必須使用Funclass才能獲得 useEffect?為什么我們的Class不能有類似的東西?答案是我們可以:

  1. class Foo extends React.Component { 
  2.    someEffect = effect((value1, value2) => { 
  3.      subscribeToA(value1, value2);     return () => { 
  4.         unsubscribeFromA();     };   })   render(){     this.someEffect(this.props.value1, this.state.value2); 
  5.     return <Text>Hello world</Text>    
  6.    }} 

effect 函數(shù)將記住給定的函數(shù),并且僅當(dāng)其參數(shù)之一已更改時(shí)才會(huì)再次調(diào)用它。通過從我們的render函數(shù)內(nèi)部觸發(fā)效果,我們可以確保它在每次渲染/更新時(shí)都被調(diào)用,但只有當(dāng)它的一個(gè)參數(shù)被改變時(shí),給定的函數(shù)才會(huì)再次運(yùn)行,所以我們在結(jié)合 componentDidMount 和 componentDidUpdate 方面實(shí)現(xiàn)了類似 useEffect 的效果,但遺憾的是,我們?nèi)匀恍枰? componentWillUnmount 中手動(dòng)進(jìn)行最后的清理。另外,從render內(nèi)調(diào)用效果函數(shù)也有點(diǎn)丑。為了得到和useEffect完全一樣的效果,React需要增加對它的支持。

最重要的是 useEffect 不應(yīng)該被認(rèn)為是進(jìn)入funclass的有效動(dòng)機(jī),它本身就是一個(gè)有效的動(dòng)機(jī),也可以為類實(shí)現(xiàn)。

動(dòng)機(jī)4:性能

React團(tuán)隊(duì)說類很難優(yōu)化和最小化,funclass應(yīng)該以某種方式改進(jìn),關(guān)于這件事,我只有一件事要說——給我看看數(shù)字。

我至今找不到任何論文,也沒有我可以克隆并運(yùn)行以比較Funclasses VS Class的性能的基準(zhǔn)演示應(yīng)用程序。事實(shí)上,我們沒有看到這樣的演示并不奇怪——Funclasses需要以某種方式實(shí)現(xiàn)這個(gè)功能(如果你喜歡的話,也可以用Ref),所以我很期待那些讓類難以優(yōu)化的問題,也會(huì)影響到Funclasses。

不管怎么說,所有關(guān)于性能的爭論,在不展示數(shù)據(jù)的情況下實(shí)在是一文不值,所以我們真的不能把它作為論據(jù)。

動(dòng)機(jī)5:Funclass不太冗長

你可以找到很多通過將Class轉(zhuǎn)換為Funclass來減少代碼的例子,但大多數(shù)甚至所有的例子都利用了 useEffect 鉤子,以便將 componentDidMount 和 componentWillUnmount 結(jié)合在一起,從而達(dá)到極大的效果。

但正如我前面所說,useEffect 不應(yīng)該被認(rèn)為是Funclass的優(yōu)勢,如果忽略它所實(shí)現(xiàn)的代碼減少,那么只會(huì)留下非常小的影響。而且,如果你嘗試使用 useMemo,useCallback 等來優(yōu)化Funclass,你甚至可能得到比等效類更冗長的代碼。

當(dāng)比較小而瑣碎的組件時(shí),F(xiàn)unclasses毫無疑問地贏了,因?yàn)轭愑幸恍┕逃械哪0澹瑹o論你的類有多小你都需要付出。但在比較大的組件時(shí),你幾乎看不出差別,有時(shí)正如我所說,類甚至可以更干凈。

最后,我不得不對 useContext 說幾句:useContext其實(shí)比我們目前原有的類的context API有很大的改進(jìn)。但是再一次,為什么我們不能為類也有這樣漂亮而簡潔的API呢? 為什么我們不能做這樣的事情。

  1. //inside "./someContext" : 
  2. export const someContext = React.Context({helloText: 'bla'}); 
  3. //inside "Foo": 
  4. import {someContext} from './someContext'; 
  5. class Foo extends React.component { 
  6.    render() { 
  7.       <View> 
  8.         <Text>{someContext.helloText}</Text> 
  9.       </View> 
  10.    } 

當(dāng)上下文中的 helloText 發(fā)生變化時(shí),組件應(yīng)該重新渲染以反映這些變化。就是這樣,不需要丑陋的高階組件(HOC)。

那么,為什么React團(tuán)隊(duì)選擇只改進(jìn)useContext API而不是常規(guī)content API?我不知道,但這并不意味著Funclass本質(zhì)上更干凈。這意味著React應(yīng)該通過為類實(shí)現(xiàn)相同的API改進(jìn)來做得更好。

因此,在提出有關(guān)動(dòng)機(jī)的問題之后,讓我們看一下我不喜歡的有關(guān)Funclass的其他內(nèi)容。

隱藏的副作用

在Funclasses的 useEffect 實(shí)現(xiàn)中,最讓我困擾的一件事,就是沒有弄清楚某個(gè)組件的副作用是什么。對于類,如果你想知道一個(gè)組件在掛載時(shí)做了什么,你可以很容易地檢查 componentDidMount 中的代碼或檢查構(gòu)造函數(shù)。如果你看到一個(gè)重復(fù)的調(diào)用,你可能應(yīng)該檢查一下 componentDidUpdate,有了新的 useEffect 鉤子,副作用可以深深地嵌套在代碼中。

假設(shè)我們檢測到一些不必要的服務(wù)器調(diào)用,我們查看可疑組件的代碼,然后看到以下內(nèi)容:

  1. const renderContacts = (props) => { 
  2.   const [contacts, loadMoreContacts] = useContacts(props.contactsIds); 
  3.   return ( 
  4.     <SmartContactList contacts={contacts}/> 
  5.   ) 

這里沒什么特別的,我們應(yīng)該研究 SmartContactList,還是應(yīng)該深入研究 useContacts?讓我們深入研究一下 useContacts 吧:

  1. export const useContacts = (contactsIds) => { 
  2.   const {loadedContacts, loadingStatus}  = useContactsLoader();  const {isRefreshing, handleSwipe} = useSwipeToReresh(loadingStatus);  // ... many other useX() functions 
  3.   useEffect(() => { 
  4.     //** 很多代碼,都與一些加載聯(lián)系人的動(dòng)畫有關(guān)。*// 
  5.     }, [loadingStatus]);    //..rest of code 

好的,開始變得棘手。隱藏的副作用在哪里?如果我們深入研究 useSwipeToRefresh,我們將看到:

  1. export const useSwipeToRefresh = (loadingStatus) => { 
  2.   // ..lot's of code 
  3.   // ... 
  4.    
  5.   useEffect(() => { 
  6.     if(loadingStatus === 'refresing') { 
  7.        refreshContacts(); // bingo! 我們隱藏的副作用 
  8.     }   
  9.   }); //<== 我們忘記了依賴項(xiàng)數(shù)組! 

我們發(fā)現(xiàn)了我們的隱藏效果,refreshContacts 會(huì)在每個(gè)組件渲染時(shí)意外地調(diào)用fetch contacts。在大型代碼庫和某些結(jié)構(gòu)不良的組件中,嵌套的 useEffect 可能會(huì)造成麻煩。

我并不是說你不能用類編寫糟糕的代碼,但是Funclasses更容易出錯(cuò),而且沒有嚴(yán)格定義生命周期方法的結(jié)構(gòu),更容易做糟糕的事情。

膨脹的API

通過在類的同時(shí)增加鉤子API,React的API實(shí)際上增加了一倍。現(xiàn)在每個(gè)人都需要學(xué)習(xí)兩種完全不同的方法,我必須說,新API比舊API晦澀得多。一些簡單的事情,如獲得之前的props和state,現(xiàn)在都成了很好的面試材料。你能寫一個(gè)鉤子獲得之前得 props 在不借助google的情況下?

像React這樣的大型庫必須非常小心地在API中添加如此巨大的更改,這樣做的動(dòng)機(jī)甚至是不合理的。

缺乏說明性

在我看來,F(xiàn)unclass比類更混亂。例如,要找到組件的切入點(diǎn)就比較困難——用classes只需搜索 render 函數(shù),但用Funclasses就很難發(fā)現(xiàn)主return語句。另外,要按照不同的 useEffect 語句來理解組件的流程是比較困難的,相比之下,常規(guī)的生命周期方法會(huì)給你一些很好的提示,讓你知道自己的代碼需要在哪里尋找。如果我正在尋找某種初始化邏輯,我將跳轉(zhuǎn)(VSCode中的cmd + shift + o)到 componentDidMount,如果我正在尋找某種更新機(jī)制,則可能會(huì)跳到 componentDidUpdate 等。通過Funclass,我發(fā)現(xiàn)很難在大型組件內(nèi)部定位。

約定驅(qū)動(dòng)的API

鉤子的主要規(guī)則(可能也是最重要的規(guī)則)之一是使用前綴約定。

就是感覺不對

你知道有什么不對勁的感覺嗎?這就是我對鉤子的感覺。有時(shí)我能準(zhǔn)確地指出問題所在,但有時(shí)只是一種普遍的感覺,即我們走錯(cuò)了方向。當(dāng)你發(fā)現(xiàn)一個(gè)好的概念時(shí),你可以看到事情是如何很好地結(jié)合在一起的,但是當(dāng)你在為錯(cuò)誤的概念而苦惱的時(shí)候,發(fā)現(xiàn)你需要添加更多更具體的東西和規(guī)則,才能讓事情順利進(jìn)行。

有了鉤子,就會(huì)有越來越多奇怪的東西跳出來,有更多“有用的”鉤子可以幫助你做一些瑣碎的事情,也有更多的東西需要學(xué)習(xí)。如果我們需要這么多的utils在我們的日常工作中,只是為了隱藏一些奇怪的復(fù)雜,這是一個(gè)巨大的跡象,說明我們走錯(cuò)了路。

幾年前,當(dāng)我從Angular 1.5轉(zhuǎn)到React時(shí),我驚訝于React的API是如此簡單,文檔是如此的薄。Angular曾經(jīng)有龐大的文檔,你可能要花上幾天的時(shí)間才能涵蓋所有內(nèi)容——消化機(jī)制、不同的編譯階段、transclude、綁定、模板等等。光是這一點(diǎn)就給我很大的啟示,而React它簡潔明了,你可以在幾個(gè)小時(shí)內(nèi)把整個(gè)文檔看一遍就可以了。在第一次,第二次以及以后的所有次嘗試使用鉤子的過程中,我發(fā)現(xiàn)自己有義務(wù)一次又一次地使用文檔。

總結(jié)

我討厭成為聚會(huì)的掃興者,但我真的認(rèn)為Hooks可能是React社區(qū)發(fā)生的第2件最糟糕的事情(第一名仍然由Redux占據(jù))。它給已經(jīng)脆弱的生態(tài)系統(tǒng)增加了另一場毫無用處的爭論,目前尚不清楚鉤子是否是推薦的使用方式,還是只是另一個(gè)功能和個(gè)人品味的問題。

我希望React社區(qū)能夠醒來,并要求在Funclass和class的功能之間保持平衡。我們可以在類中擁有更好的Context API,并且可以為類提供諸如useEffect之類的東西。如果需要,React應(yīng)該讓我們選擇繼續(xù)使用類,而不是通過僅為Funclass添加更多功能而強(qiáng)行殺死它而將類拋在后面。

另外,早在2017年底,我就曾以《Redux的丑陋面》為題發(fā)表過一篇文章,如今連Redux的創(chuàng)造者Dan Abramov都已經(jīng)承認(rèn)Redux是一個(gè)巨大的錯(cuò)誤。

React Hooks的丑陋一面

只是歷史在重演嗎?時(shí)間會(huì)證明一切。

無論如何,我和我的隊(duì)友決定暫時(shí)堅(jiān)持用類,并使用基于Mobx的解決方案作為狀態(tài)管理工具。我認(rèn)為,在獨(dú)立開發(fā)人員和團(tuán)隊(duì)工作人員之間,Hooks的普及率存在很大差異——Hooks的不良性質(zhì)在大型代碼庫中更加明顯,你需要在該代碼庫中處理其他人的代碼。我個(gè)人真的希望React能把 ctrl+z 的鉤子全部放在一起。

我打算開始著手制定一個(gè)RFC,為React提出一個(gè)簡單、干凈、內(nèi)置的狀態(tài)管理方案,一勞永逸地解決共享狀態(tài)邏輯的問題,希望能用一種比Funclasses不那么笨拙的方式。

 

責(zé)任編輯:趙寧寧 來源: 今日頭條
相關(guān)推薦

2018-12-25 09:39:14

2022-05-11 22:15:51

云計(jì)算云平臺(tái)

2009-07-30 14:38:36

云計(jì)算

2011-12-22 20:53:40

Android

2011-12-23 09:43:15

開源開放

2024-05-15 16:41:57

進(jìn)程IO文件

2019-08-20 15:16:26

Reacthooks前端

2012-12-19 09:04:29

2025-04-01 08:40:00

HTTPRPC開發(fā)

2024-11-11 16:40:04

2021-05-11 08:48:23

React Hooks前端

2023-11-06 08:00:00

ReactJavaScript開發(fā)

2013-09-16 10:52:09

2020-10-28 09:12:48

React架構(gòu)Hooks

2022-03-22 09:09:17

HookReact前端

2020-07-13 23:22:02

物聯(lián)網(wǎng)電子技術(shù)

2013-05-07 10:06:20

2025-03-07 00:11:00

JWTJSONSession

2021-03-18 08:00:55

組件Hooks React

2022-03-31 17:54:29

ReactHooks前端
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 91九色视频| av手机在线播放 | 国产激情毛片 | av中文天堂 | 免费观看日韩av | 亚洲精选一区二区 | 龙珠z在线观看 | 日韩在线欧美 | 亚洲第一天堂无码专区 | 日韩三区在线 | 亚洲精品一区二区三区中文字幕 | 国产精品一区二区三 | 性国产xxxx乳高跟 | 精品国产伦一区二区三区观看说明 | h视频网站在线观看 | 亚洲免费视频网站 | 国产最新网址 | 日本黄色激情视频 | 成人国产精品久久 | 日本精品一区二区三区在线观看视频 | 久久精品亚洲欧美日韩精品中文字幕 | 精品成人69xx.xyz | 久久国产精品免费 | 欧美一区二区三区视频 | 欧美一区二区三区 | 精品一区二区三 | 精品久久久久久久久久久下田 | 日韩欧美国产精品综合嫩v 一区中文字幕 | 美女视频一区二区 | 亚洲精品一区二区三区在线 | 99日韩| 成人免费久久 | 精品国产精品一区二区夜夜嗨 | 成人午夜免费视频 | 97久久精品午夜一区二区 | 亚洲在线一区二区三区 | 久久九精品| 91精品久久久久久久久中文字幕 | 久久在视频 | 精精精精xxxx免费视频 | 888久久久 |