真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

淺談React異步組件的使用方法

本篇內(nèi)容介紹了“React異步組件的使用方法”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

創(chuàng)新互聯(lián)建站長(zhǎng)期為千余家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為吉安企業(yè)提供專業(yè)的成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站,吉安網(wǎng)站改版等技術(shù)服務(wù)。擁有十載豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。

一 前言

今天我們聊一聊React中的異步組件的現(xiàn)況和未來(lái),異步組件很可能是未來(lái)從數(shù)據(jù)交互到UI展示一種流暢的技術(shù)方案,所以既然要吃透React,進(jìn)階React,就有必要搞懂異步組件。

老規(guī)矩,我們還是帶著問(wèn)題開(kāi)始今天的思考?(自測(cè)掌握程度)

  • 1 什么是React異步組件,解決什么問(wèn)題?

  • 2 componentDidCatch如何捕獲到渲染階段錯(cuò)誤,又這么彌補(bǔ)。

  • 3 React.lazy如何實(shí)現(xiàn)動(dòng)態(tài)加載的?

  • 4 React.lazy為什么要在Supsonse內(nèi)部。

  • 5 Supsonse原理是什么?

二 初識(shí):異步組件

1 什么是異步組件

我們先來(lái)想想目前的React應(yīng)用中使用ajax或者fetch進(jìn)行數(shù)據(jù)交互場(chǎng)景,基本上就是這樣的,在類組件中componentDidMount和函數(shù)組件effect中進(jìn)行數(shù)據(jù)交互,得到數(shù)據(jù)后,再渲染UI視圖。那么可不可以讓組件的渲染等待異步數(shù)據(jù)請(qǐng)求完畢,得到數(shù)據(jù)后再進(jìn)行render呢?

對(duì)于上面這種情況,第一感覺(jué)是難以置信,如果能夠?qū)崿F(xiàn)讓渲染中斷,等到數(shù)據(jù)請(qǐng)求之后,再渲染呢?那就是Susponse,上面說(shuō)到的不可能實(shí)現(xiàn)的事,Susponse做到了,React  16.6 新增了,Susponse 讓組件“等待”某個(gè)異步操作,直到該異步操作結(jié)束即可渲染。

傳統(tǒng)模式:渲染組件-> 請(qǐng)求數(shù)據(jù) -> 再渲染組件。

異步模式:請(qǐng)求數(shù)據(jù)-> 渲染組件。

2 開(kāi)啟Suspense模式

一個(gè)傳統(tǒng)模式下的數(shù)據(jù)交互應(yīng)該是這個(gè)樣子的。

function Index(){     const [ userInfo , setUserInfo ] = React.useState(0)     React.useEffect(()=>{        /* 請(qǐng)求數(shù)據(jù)交互 */        getUserInfo().then(res=>{            setUserInfo(res)        })     },[])     return 
         

{userInfo.name}

;     
 } export default function Home(){     return 
              
 }

流程:頁(yè)面初始化掛載,useEffect里面請(qǐng)求數(shù)據(jù),通過(guò)useState改變數(shù)據(jù),二次更新組件渲染數(shù)據(jù)。

那么如果用Susponse異步模式就可以這么寫(xiě):

function FutureAsyncComponent (){     const userInfo = getUserInfo()     return 
         

{userInfo.name}

;      
 }  /* 未來(lái)的異步模式 */ export default function Home(){    return 
        loading... 
 } >                      
 }

當(dāng)數(shù)據(jù)還沒(méi)有加載完成時(shí)候,會(huì)展示Suspense中 fallback的內(nèi)容,彌補(bǔ)請(qǐng)求數(shù)據(jù)中過(guò)渡效果 ,盡管這個(gè)模式在現(xiàn)在版本中還不能正式使用,但是將來(lái)  React 會(huì)支持這樣的代碼形式。

三 溯源:從componentDidCatch到Suspense

至于Suspense是如何將上述不可能的事情變成可能的呢?這就要從 componentDidCatch 說(shuō)起了,在 React 推出 v16  的時(shí)候,就增加了一個(gè)新生命周期函數(shù) componentDidCatch。如果某個(gè)組件定義了  componentDidCatch,那么這個(gè)組件中所有的子組件在渲染過(guò)程中拋出異常時(shí),這個(gè) componentDidCatch 函數(shù)就會(huì)被調(diào)用。

componentDidCatch使用

componentDidCatch 可以捕獲異常,它接受兩個(gè)參數(shù):

1 error —— 拋出的錯(cuò)誤。

2 info —— 帶有 componentStack key 的對(duì)象,其中包含有關(guān)組件引發(fā)錯(cuò)誤的棧信息。

我們來(lái)模擬一個(gè)子組件渲染失敗的情況:

/* 正常組件,可以渲染 */ function Children(){   return 
 hello ,let us learn React 
 }  /* 非React組件,將無(wú)法正常渲染 */ function Children1(){   return  } export default class Index extends React.Component{   componentDidCatch(error,info){       console.log(error,info)   }   render(){     return 
                   
   } }

如上,我們模擬一個(gè)render失敗的場(chǎng)景,將一個(gè)非React組件Children1當(dāng)作正常的React的組件來(lái)渲染,這樣在渲染階段就會(huì)報(bào)錯(cuò),錯(cuò)誤信息就會(huì)被  componentDidCatch捕獲到,錯(cuò)誤信息如下:

淺談React異步組件的使用方法

對(duì)于如上如果在渲染子組件的時(shí)候出現(xiàn)錯(cuò)誤,會(huì)導(dǎo)致整個(gè)組件渲染失敗,無(wú)法顯示,正常的組件Children也會(huì)被牽連,這個(gè)時(shí)候我們需要在componentDidCatch做一些補(bǔ)救措施,比如我們發(fā)現(xiàn)  componentDidCatch 失敗,可以給Children1加一個(gè)狀態(tài)控制,如果渲染失敗,那么終止Children1的render。

function ErroMessage(){   return 
渲染出現(xiàn)錯(cuò)誤~
 }  export default class Index extends React.Component{   state={ errorRender:false }   componentDidCatch(error,info){       /* 補(bǔ)救措施 */       this.setState({         errorRender:true       })   }   render(){     return 
              { this.state.errorRender ?  :   }     
   } }

淺談React異步組件的使用方法

如果出現(xiàn)錯(cuò)誤,通過(guò)setState重新渲染,并移除失敗的組件,這樣組件就能正常渲染了,同樣也不影響Children掛載。componentDidCatch一方面捕獲在渲染階段出現(xiàn)的錯(cuò)誤,另一方面可以在生命周期的內(nèi)部執(zhí)行副作用去挽回渲染異常帶來(lái)的損失。

componentDidCatch原理

componentDidCatch原理應(yīng)該很好理解,內(nèi)部可以通過(guò)try{}catch(error){}來(lái)捕獲渲染錯(cuò)誤,處理渲染錯(cuò)誤。

try {   //嘗試渲染子組件 } catch (error) {   // 出現(xiàn)錯(cuò)誤,componentDidCatch被調(diào)用, }

componentDidCatch思想能否遷移到Suspense上

那么回到我們的異步組件上來(lái),如果讓異步的代碼放在同步執(zhí)行,是肯定不會(huì)正常的渲染的,我們還是要先請(qǐng)求數(shù)據(jù),等到數(shù)據(jù)返回,再用返回的數(shù)據(jù)進(jìn)行渲染,那么重點(diǎn)在于這個(gè)等字,如何讓同步的渲染停止下來(lái),去等異步的數(shù)據(jù)請(qǐng)求呢?拋出異常可以嗎?  異常可以讓代碼停止執(zhí)行,當(dāng)然也可以讓渲染中止。

Suspense 就是用拋出異常的方式中止的渲染,Suspense 需要一個(gè) createFetcher 函數(shù)會(huì)封裝異步操作,當(dāng)嘗試從  createFetcher 返回的結(jié)果讀取數(shù)據(jù)時(shí),有兩種可能:一種是數(shù)據(jù)已經(jīng)就緒,那就直接返回結(jié)果;還有一種可能是異步操作還沒(méi)有結(jié)束,數(shù)據(jù)沒(méi)有就緒,這時(shí)候  createFetcher 會(huì)拋出一個(gè)“異常”。

這個(gè)“異常”是正常的代碼錯(cuò)誤嗎?非也,這個(gè)異常是封裝請(qǐng)求數(shù)據(jù)的Promise對(duì)象,里面是真正的數(shù)據(jù)請(qǐng)求方法,既然 Suspense  能夠拋出異常,就能夠通過(guò)類似 componentDidCatch的try{}catch{}去獲取這個(gè)異常。

獲取這個(gè)異常之后干什么呢?  我們知道這個(gè)異常是Promise,那么接下來(lái)當(dāng)然是執(zhí)行這個(gè)Promise,在成功狀態(tài)后,獲取數(shù)據(jù),然后再次渲染組件,此時(shí)的渲染就已經(jīng)讀取到正常的數(shù)據(jù),那么可以正常的渲染了。接下來(lái)我們模擬一下createFetcher和Suspense

我們模擬一個(gè)簡(jiǎn)單createFetcher

/**  *   * @param {*} fn  我們請(qǐng)求數(shù)據(jù)交互的函數(shù),返回一個(gè)數(shù)據(jù)請(qǐng)求的Promise   */ function createFetcher(fn){     const fetcher = {         status:'pedding',         result:null,         p:null     }     return function (){       const getDataPromise = fn()       fetcher.p = getDataPromise       getDataPromise.then(result=>{ /* 成功獲取數(shù)據(jù) */          fetcher.result = result           fetcher.status = 'resolve'       })          if(fetcher.status === 'pedding'){ /* 第一次執(zhí)行中斷渲染,第二次 */          throw fetcher       }       /* 第二次執(zhí)行 */       if(fetcher.status)       return fetcher.result     } }

我們模擬一個(gè)簡(jiǎn)單的Suspense

export class Suspense extends React.Component{    state={ isRender: true  }    componentDidCatch(e){      /* 異步請(qǐng)求中,渲染 fallback */      this.setState({ isRender:false })      const { p } = e      Promise.resolve(p).then(()=>{        /* 數(shù)據(jù)請(qǐng)求后,渲染真實(shí)組件 */        this.setState({ isRender:true })      })    }    render(){      const { isRender } = this.state      const { children , fallback } = this.props      return isRender ? children : fallback    } }

用 componentDidCatch 捕獲異步請(qǐng)求,如果有異步請(qǐng)求渲染  fallback,等到異步請(qǐng)求執(zhí)行完畢,渲染真實(shí)組件,借此整個(gè)異步流程完畢。但為了讓大家明白流程,只是一次模擬異步的過(guò)程,實(shí)際流程要比這個(gè)復(fù)雜的多。

流程圖:

淺談React異步組件的使用方法

四 實(shí)踐:從Suspense到React.lazy

React.lazy簡(jiǎn)介

Suspense帶來(lái)的異步組件的革命還沒(méi)有一個(gè)實(shí)質(zhì)性的成果,目前版本沒(méi)有正式投入使用,但是React.lazy是目前版本Suspense的最佳實(shí)踐。我們都知道React.lazy配合Suspense可以實(shí)現(xiàn)懶加載,按需加載,這樣很利于代碼分割,不會(huì)讓初始化的時(shí)候加載大量的文件,減少首屏?xí)r間。

React.lazy基本使用

const LazyComponent = React.lazy(()=>import('./text'))

React.lazy接受一個(gè)函數(shù),這個(gè)函數(shù)需要?jiǎng)討B(tài)調(diào)用 import()。它必須返回一個(gè) Promise ,該 Promise需要 resolve 一個(gè)  default export 的 React 組件。

我們先來(lái)看一下基本使用:

const LazyComponent = React.lazy(() => import('./test.js'))  export default function Index(){    return loading...
} >             }

我們用Promise模擬一下 import()效果,將如上 LazyComponent改成如下的樣子:

function Test(){   return 《React進(jìn)階實(shí)踐指南》即將上線~
 } const LazyComponent =  React.lazy(()=> new Promise((resolve)=>{   setTimeout(()=>{       resolve({           default: ()=>        })   },2000) }))

效果:

淺談React異步組件的使用方法

React.lazy原理解讀

React.lazy 是如何配合Susponse  實(shí)現(xiàn)動(dòng)態(tài)加載的效果的呢?實(shí)際上,lazy內(nèi)部就是做了一個(gè)createFetcher,而上面講到createFetcher得到渲染的數(shù)據(jù),而lazy里面自帶的createFetcher異步請(qǐng)求的是組件。lazy內(nèi)部模擬一個(gè)promiseA規(guī)范場(chǎng)景。我們完全可以理解React.lazy用Promise模擬了一個(gè)請(qǐng)求數(shù)據(jù)的過(guò)程,但是請(qǐng)求的結(jié)果不是數(shù)據(jù),而是一個(gè)動(dòng)態(tài)的組件。

接下來(lái)我們看一下lazy是如何處理的

function lazy(ctor){     return {          $$typeof: REACT_LAZY_TYPE,          _payload:{             _status: -1,  //初始化狀態(tài)             _result: ctor,          },          _init:function(payload){              if(payload._status===-1){ /* 第一次執(zhí)行會(huì)走這里  */                 const ctor = payload._result;                 const thenable = ctor();                 payload._status = Pending;                 payload._result = thenable;                 thenable.then((moduleObject)=>{                     const defaultExport = moduleObject.default;                     resolved._status = Resolved; // 1 成功狀態(tài)                     resolved._result = defaultExport;/* defaultExport 為我們動(dòng)態(tài)加載的組件本身  */                  })              }             if(payload._status === Resolved){ // 成功狀態(tài)                 return payload._result;             }             else {  //第一次會(huì)拋出Promise異常給Suspense                 throw payload._result;              }          }     } }

React.lazy包裹的組件會(huì)標(biāo)記REACT_LAZY_TYPE類型的element,在調(diào)和階段會(huì)變成 LazyComponent  類型的fiber,React對(duì)LazyComponent會(huì)有單獨(dú)的處理邏輯,第一次渲染首先會(huì)執(zhí)行 _init  方法。此時(shí)這個(gè)_init方法就可以理解成createFetcher。

我們看一下lazy中init函數(shù)的執(zhí)行:

react-reconciler/src/ReactFiberBeginWork.js

function mountLazyComponent(){     const init = lazyComponent._init;     let Component = init(payload); }

流程圖

淺談React異步組件的使用方法

五 展望:Suspense未來(lái)可期

你當(dāng)下并不使用 Relay,那么你暫時(shí)無(wú)法在應(yīng)用中試用 Suspense。因?yàn)槠駷橹梗趯?shí)現(xiàn)了 Suspense 的庫(kù)中,Relay  是我們唯一在生產(chǎn)環(huán)境測(cè)試過(guò),且對(duì)它的運(yùn)作有把握的一個(gè)庫(kù)。

目前Suspense還并不能,如果你想使用,可以嘗試一下在生產(chǎn)環(huán)境使用集成了 Suspense 的 Relay。Relay 指南!

Suspense能解決什么?

Suspense面臨挑戰(zhàn)?

對(duì)于未來(lái)的Suspense能否作為主流異步請(qǐng)求數(shù)據(jù)渲染的方案,筆者認(rèn)為Suspense未來(lái)還是充滿期待,那么對(duì)于Suspense的挑戰(zhàn),個(gè)人感覺(jué)在于以下幾個(gè)方面:

1  concurrent模式下的Susponse可以帶來(lái)更好的用戶體驗(yàn),react團(tuán)隊(duì)能夠讓未來(lái)的Suspense更靈活,有一套更清晰明確的createFetcher制作手冊(cè),是未來(lái)的concurrent模式下Suspense脫穎而出的關(guān)鍵。

2 Suspense能否廣泛使用,更在于 Suspense 的生態(tài)發(fā)展,有一個(gè)穩(wěn)定的數(shù)據(jù)請(qǐng)求庫(kù)與Suspense完美契合。

3  開(kāi)發(fā)者對(duì)Suspense的價(jià)值的認(rèn)可,如果Suspense在未來(lái)的表現(xiàn)力更出色的話,會(huì)有更多開(kāi)發(fā)者寧愿自己封裝一套數(shù)據(jù)請(qǐng)求方法,給優(yōu)秀的Suspense買(mǎi)單。

“React異步組件的使用方法”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!


分享名稱:淺談React異步組件的使用方法
網(wǎng)站路徑:http://weahome.cn/article/gooded.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部