1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        【React】668- React Hooks的優(yōu)缺點

        共 4381字,需瀏覽 9分鐘

         ·

        2020-08-01 02:43

        https://zhihu.com/people/zhan-zi-zhen-84

        下面我談一下我認為的react hooks的優(yōu)缺點,優(yōu)缺點通過和傳統(tǒng)的React.Component進行對比得出。

        優(yōu)點

        一、更容易復用代碼

        這點應該是react hooks最大的優(yōu)點,它通過自定義hooks來復用狀態(tài),從而解決了類組件有些時候難以復用邏輯的問題。hooks是怎么解決這個復用的問題呢,具體如下:

        每調(diào)用useHook一次都會生成一份獨立的狀態(tài),這個沒有什么黑魔法,函數(shù)每次調(diào)用都會開辟一份獨立的內(nèi)存空間。雖然狀態(tài)(from useState)和副作用(useEffect)的存在依賴于組件,但它們可以在組件外部進行定義。這點是class component做不到的,你無法在外部聲明state和副作用(如componentDidMount)。上面這兩點,高階組件和renderProps也同樣能做到。但hooks實現(xiàn)起來的代碼量更少,以及更直觀(代碼可讀性)。

        舉個例子,我們經(jīng)常使用的antd-table,我們經(jīng)常需要寫一些狀態(tài):pagination={current:xxx,pageSize:xxx,total:xxx}。但許多場景只是簡單的表格,我們希望封裝一個高階組件,自帶這些狀態(tài),并可以自動調(diào)用server去獲取remote data。

        用高階組件來實現(xiàn)這樣它:

        import?{?Table?}?from?'antd'
        import?server?from?'./api'
        @useTable(server)
        class?App?extends?Component{
        ??render(){
        ????//?useTable和tableProps的代碼是分離的,但高階組件一多,代碼會變得較難閱讀,
        ???//?你難以區(qū)分這個props是來自哪個高階組件,或者還是來自業(yè)務的父組件。
        ????const?{?tableProps?}?=?this.props;
        ????return?(
        ??????<Table?
        ????????columns={[...]}
        ??????//?tableProps包含pagination,?onChange,?dataSource等屬性
        ????????{...tableProps}
        ??????/>

        ????)
        ??}
        }

        用hooks來實現(xiàn)的話,會是:

        import?{?Table?}?from?'antd'
        import?server?from?'./api'
        function?App?{
        ????const?{?tableProps?}?=?useTable();
        ????return?(
        ??????<Table?
        ????????columns={[...]}
        ??????//?tableProps包含pagination,?onChange,?dataSource等屬性
        ????????{...tableProps}
        ??????/>

        ????)
        }
        /*
        相對比高階組件“祖父=>父=>子”的層層嵌套,
        hooks是這樣的:??
        const?{?brother1?}?=?usehook1;?
        const?{?brother2}?=?usehook2;
        */

        實現(xiàn)有以下幾點優(yōu)勢:

        把"useTable"和輸出的值寫到一起,結(jié)構(gòu)更清晰,更容易閱讀和維護。對比高階組件,代碼量更少。

        二、清爽的代碼風格

        函數(shù)式編程風格,函數(shù)式組件、狀態(tài)保存在運行環(huán)境、每個功能都包裹在函數(shù)中,整體風格更清爽,更優(yōu)雅。另外,對比類組件,函數(shù)組件里面的unused狀態(tài)和unused-method更容易被發(fā)現(xiàn)。

        三、代碼量更少

        向props或狀態(tài)取值更加方便,函數(shù)組件的取值都從當前作用域直接獲取變量,而類組件需要先訪問實例引用this,再訪問其屬性或者方法,多了一步。更改狀態(tài)也變得更加簡單, this.setState({ count:xxx })變成 setCount(xxx)。因為減少了很多模板代碼,特別是小組件寫起來更加省事,人們更愿意去拆分組件。而組件粒度越細,則被復用的可能性越大。所以,hooks也在不知不覺中改變?nèi)藗兊拈_發(fā)習慣,提高項目的組件復用率。

        缺點

        一、響應式的useEffect

        寫函數(shù)組件時,你不得不改變一些寫法習慣。你必須清楚代碼中useEffectuseCallback等api的第二個參數(shù)“依賴項數(shù)組”的改變時機,并且掌握上下文的useEffect的觸發(fā)時機。當邏輯較復雜的時候,useEffect觸發(fā)的次數(shù),可能會被你預想的多。對比componentDidmountcomponentDidUpdateuseEffect帶來的心智負擔更大。

        二、狀態(tài)不同步

        這絕對是最大的缺點。函數(shù)的運行是獨立的,每個函數(shù)都有一份獨立的作用域。函數(shù)的變量是保存在運行時的作用域里面,當我們有異步操作的時候,經(jīng)常會碰到異步回調(diào)的變量引用是之前的,也就是舊的(這里也可以理解成閉包)。

        import?React,?{?useState?}?from?"react";
        const?Counter?=?()?=>?{
        ??const?[counter,?setCounter]?=?useState(0);
        ??const?onAlertButtonClick?=?()?=>?{
        ????setTimeout(()?=>?{
        ??????alert("Value:?"?+?counter);
        ????},?3000);
        ??};
        ??return?(
        ????<div>
        ??????<p>You?clicked?{counter}?times.p>

        ??????<button?onClick={()?=>?setCounter(counter?+?1)}>Click?mebutton>
        ??????<button?onClick={onAlertButtonClick}>
        ????????Show?me?the?value?in?3?seconds
        ??????button>
        ????div>
        ??);
        };

        export?default?Counter;

        當你點擊Show me the value in 3 seconds的后,緊接著點擊Click me使得counter的值從0變成1。三秒后,定時器觸發(fā),但alert出來的是0(舊值),但我們希望的結(jié)果是當前的狀態(tài)1。

        這個問題在class component不會出現(xiàn),因為class component的屬性和方法都存放在一個instance上,調(diào)用方式是:this.state.xxxthis.method()。因為每次都是從一個不變的instance上進行取值,所以不存在引用是舊的問題。

        其實解決這個hooks的問題也可以參照類的instance。用useRef返回的immutable RefObjectcurrent屬性是可變的)來保存state,然后取值方式從counter變成了:counterRef.current。如下:

        import?React,?{?useState,?useRef,?useEffect?}?from?"react";

        const?Counter?=?()?=>?{
        ??const?[counter,?setCounter]?=?useState(0);
        ??const?counterRef?=?useRef(counter);
        ??const?onAlertButtonClick?=?()?=>?{
        ????setTimeout(()?=>?{
        ??????alert("Value:?"?+?counterRef.current);
        ????},?3000);
        ??};
        ??useEffect(()?=>?{
        ????counterRef.current?=?counter;
        ??});
        ??return?(
        ????<div>
        ??????<p>You?clicked?{counter}?times.p>

        ??????<button?onClick={()?=>?setCounter(counter?+?1)}>Click?mebutton>
        ??????<button?onClick={onAlertButtonClick}>
        ????????Show?me?the?value?in?3?seconds
        ??????button>
        ????div>
        ??);
        };

        export?default?Counter;

        結(jié)果如我們所期待,alert的是當前的值1。

        我們可以把這個過程封裝成一個custom hook,如下:

        import?{?useEffect,?useRef,?useState?}?from?"react";
        const?useRefState?=?(initialValue:?T):
        ?[T,?React.MutableRefObject,?
        ???React.Dispatch>]?=>?{
        ??const?[state,?setState]?=?useState(initialValue);
        ??const?stateRef?=?useRef(state);
        ??useEffect(()?=>?{
        ????stateRef.current?=?state;
        ??},?[state]);
        ??return?[state,?stateRef,?setState];
        };

        export?default?useRefState;

        盡管這個問題被巧妙地解決了,但它不優(yōu)雅、hack味道濃,且丟失了函數(shù)編程風格。

        怎么避免react hooks的常見問題

        1. 不要在useEffect里面寫太多的依賴項,劃分這些依賴項成多個單一功能的useEffect。其實這點是遵循了軟件設計的“單一職責模式”。
        2. 如果你碰到狀態(tài)不同步的問題,可以考慮下手動傳遞參數(shù)到函數(shù)。如:
        //?showCount的count來自父級作用域?
        const?[count,setCount]?=?useState(xxx);?
        function?showCount(){?
        ??console.log(count)?
        }?

        //?showCount的count來自參數(shù)?
        const?[count,setCount]?=?useState(xxx);?
        function?showCount(c){?
        ??console.log(c)?
        }

        但這個也只能解決一部分問題,很多時候你不得不使用上述的useRef方案。

        1. 重視eslint-plugin-react-hooks插件的警告。

        2. 復雜業(yè)務的時候,使用Component代替hooks

        感想

        目前,我通常更偏向于用hooks來寫組件,但在復雜業(yè)務中,我會更傾向于用class Component或者兩者結(jié)合的方式。hooks會是未來的主流組件編寫方式,但目前來說它還不成熟。



        1. JavaScript 重溫系列(22篇全)
        2. ECMAScript 重溫系列(10篇全)
        3. JavaScript設計模式 重溫系列(9篇全)
        4.?正則 / 框架 / 算法等 重溫系列(16篇全)
        5.?Webpack4 入門(上)||?Webpack4 入門(下)
        6.?MobX 入門(上)?||??MobX 入門(下)
        7.?70+篇原創(chuàng)系列匯總

        回復“加群”與大佬們一起交流學習~

        點擊“閱讀原文”查看70+篇原創(chuàng)文章

        點這,與大家一起分享本文吧~
        瀏覽 59
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            欧美激情乱伦 | 男女羞羞视频在线 | 欧美草逼网 | 日韩三级片无码 | 68xxxxxxxxx老师 | 色香蕉在线 | 性欧美videofree高清 | 欧美色址 | 操逼XX| 狂操熟女 |