亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

React捕獲并處理異常的方式

 更新時(shí)間:2023年11月20日 09:45:54   作者:我不是外星人  
這篇文章主要給大家介紹了React優(yōu)雅的捕獲并處理渲染異常方式,文章通過代碼示例給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下

一 前言

今天來聊一聊在 React 應(yīng)用中,如何發(fā)現(xiàn)異常并處理異常的。

JSX 是優(yōu)勢(shì)也是劣勢(shì)?

在 React 中,出現(xiàn)一次渲染異常的后果是很嚴(yán)重的。比如如下的場景:

function Comp({ data }){
  return <div>{ data.value }</div>
}
/* 頁面 */
export default function App(){
  return <div>
     <div>hello</div>
     <Comp  data={{value:'hello world'}} />
     <Comp  data={{value:'前端跨端開發(fā)指南'}} />
     <Comp  data={null} />
  </div>
} 

如上,在第三個(gè) Comp 組件渲染的時(shí)候,因?yàn)?data 傳入的值是 null ,而在渲染階段讀取了 data 下面的屬性,這個(gè)時(shí)候就會(huì)報(bào)空指針的錯(cuò)誤:Cannot read properties of null ,結(jié)果就是整個(gè)頁面都白屏。

這樣后果是嚴(yán)重的,所以 React 中要特別注意渲染數(shù)據(jù)的規(guī)范與嚴(yán)謹(jǐn)。

這個(gè)問題本質(zhì)上和 React 采用 JSX 語法而并非渲染模版有一定的關(guān)系。JSX 給 React 帶來很便利的開發(fā)體驗(yàn),開發(fā)者可以借助 JSX 靈活使用組合模式,render props 模式,Hoc 等各種設(shè)計(jì)模式,JSX 給開發(fā)者帶來了很大的發(fā)揮空間,但是凡事都有兩面性。JSX 的靈活性也帶來一定的潛在風(fēng)險(xiǎn)。

React jsx 在編譯階段,會(huì)被 babel 變成 React.Element 的形式,它的執(zhí)行是在 React 整個(gè)渲染的 render 階段執(zhí)行的,如果 React.Element 出現(xiàn)了空指針等異常,那么就會(huì)中斷 render 階段的執(zhí)行,當(dāng)然也不會(huì)執(zhí)行渲染真實(shí) DOM 的 commit 階段。所以如果是初次渲染,任何渲染動(dòng)作也就不會(huì)執(zhí)行,最終呈現(xiàn)給我們的視圖就是白屏。

那么如何處理這個(gè)問題呢?

二 渲染異常處理

componentDidCatch

還好 React 中提供了 componentDidCatch 或者 getDerivedStateFromError 生命周期,去挽救由于渲染階段出現(xiàn)問題造成 UI 界面無法顯示的情況。 我們以 componentDidCatch 為例子,看一下它是如何處理的異常。

componentDidCatch 是 React 類組件的生命周期,它接受兩個(gè)參數(shù):

1 error —— 拋出的錯(cuò)誤。 2 info —— 帶有 componentStack key 的對(duì)象,其中包含有關(guān)組件引發(fā)錯(cuò)誤的棧信息。 先來打印一下,生命周期 componentDidCatch 參數(shù)長什么樣子。

那么 componentDidCatch 中可以再次觸發(fā) setState,來降級(jí) UI 渲染,componentDidCatch 會(huì)在 commit 階段被調(diào)用,因此允許執(zhí)行副作用。我們給上面的例子用類組件和 componentDidCatch 改造,如下:

function Comp({ data }){
  return <div>{ data.value }</div>
}

class CompSafe extends React.Component{
  state = {
    isError:false
  }
  componentDidCatch(){
    this.setState({ isError:true })
  }
  render(){
    const { isError } = this.state
    return isError ? null : <Comp {...this.props} />
  }
}

export default function App(){
  return <div>
     <div>hello</div>
     <CompSafe  data={{value:'hello world'}} />
     <CompSafe  data={{value:'前端跨端開發(fā)指南'}} />
     <CompSafe  data={null} />
  </div>
} 

如上,我們將 Comp 組件包裝一層,通過 CompSafe 包裹,然后 CompSafe 內(nèi)容通過 componentDidCatch 來捕獲異常,這樣就可以將渲染異常產(chǎn)生的影響,由頁面維護(hù),降低到了組件維度。其他部分的視圖也能夠正常渲染了。

但是這樣同樣暴露出一個(gè)問題。就是我們把所有的組件,都像 Comp 一樣,在配套一個(gè)渲染異常的組件 CompSafe, 那樣是不切實(shí)際的,所以我們需要一個(gè)通用能力,這樣就需要一個(gè)渲染異常的高級(jí)組件來解決。

hoc 高階組件模式也是 React 比較常用的一種包裝強(qiáng)化模式之一,高階函數(shù)是接收一個(gè)函數(shù),返回一個(gè)函數(shù),而所謂高階組件,就是接收一個(gè)組件,返回一個(gè)組件,返回的組件是根據(jù)需要對(duì)原始組件的強(qiáng)化。

HOC 助力渲染異常組件

我們接下來編寫一個(gè)通用高階組件,解決渲染異常。

function SafeCompHoc(Comp) {
  return class CompSafe extends React.Component{
    state = {
      isError:false
    }
    componentDidCatch(){
      this.setState({ isError:true })
    }
    render(){
      const { isError } = this.state
      return isError ? <div>渲染異常</div> : <Comp {...this.props} />
    }
  }
}

const CompSafe = SafeCompHoc(Comp)
export default function App(){
  return <div>
     <div>hello</div>
     <CompSafe  data={{value:'hello world'}} />
     <CompSafe  data={{value:'前端跨端開發(fā)指南'}} />
     <CompSafe  data={null} />
  </div>
} 

如上,經(jīng)過 SafeCompHoc 包裝之后的,可以批量處理渲染異常的組件,可能出現(xiàn)渲染異常的核心組件,就可以用 SafeCompHoc 統(tǒng)一處理了。

三 渲染異常監(jiān)控

渲染監(jiān)控:

如上通過 HOC 的方式做到了渲染降級(jí),但是如果只做到監(jiān)控級(jí)別,那是遠(yuǎn)遠(yuǎn)不夠的,我們要做的就是,發(fā)現(xiàn)問題,去根本解決問題,這種渲染問題大概率可能是渲染數(shù)據(jù)結(jié)構(gòu)出現(xiàn)了問題,而數(shù)據(jù)結(jié)構(gòu)大概率又是后端返回的,所以這個(gè)異常本質(zhì)上很可能是服務(wù)端出了問題。

這個(gè)時(shí)候,發(fā)現(xiàn)問題也是非常重要的,那么就需要一個(gè)渲染的監(jiān)控方法。 接下來我們將用context 上下文 + 插槽的方案來實(shí)現(xiàn)一個(gè)渲染模版監(jiān)控方案。

渲染插槽+context上下文

技術(shù)方案: 核心技術(shù)實(shí)現(xiàn):context + 插樁組件

  • 首先,我們用 context 保存一個(gè)記錄模版狀態(tài)的方法集合。在頁面初始化之后, 接下來會(huì)請(qǐng)求數(shù)據(jù),在請(qǐng)求數(shù)據(jù)之后,頁面會(huì)循環(huán)渲染子組件列表,在渲染之前,記錄每一個(gè) API 返回的模版,每一個(gè)模版需要有一個(gè)唯一標(biāo)識(shí)。
  • 每一個(gè)渲染模版里面有一個(gè)插樁組件,插樁組件在每一個(gè)模版下部,確保組件正常渲染,插樁組件一定會(huì)渲染。插樁組件的生命周期 componentDidMount 或者 useLayoutEffect 里面,觸發(fā)事件給最上層組件,并上報(bào)該模版的唯一標(biāo)識(shí)。
  • 根組件在完成首次渲染之后,通過短暫的延時(shí)后,對(duì)比渲染列表里面的每一個(gè)模版的標(biāo)識(shí),是否均備插樁組件上報(bào),如果有個(gè)別組件的標(biāo)識(shí)沒有上報(bào),則認(rèn)為是該組件渲染異常。如果有子組件發(fā)生渲染異常,上報(bào)該子組件的渲染數(shù)據(jù)。方便查詢問題。

原理圖:

介紹完原理來看一下代碼的實(shí)現(xiàn):

渲染插樁組件:

import React from 'react'
/* 上下文保存渲染異常狀態(tài) */
export const RenderErrorContext = React.createContext()
/* 渲染插樁組件 */
export default function RenderErrorComponent({renderKey}){
    const { setRenderKey } = React.useContext(RenderErrorContext)
    React.useLayoutEffect(()=>{
        /* 渲染正常,上報(bào)渲染 key */
        setRenderKey && setRenderKey(renderKey)
    },[])
    return <React.Fragment />
}

如上編寫的渲染插樁組件 RenderErrorComponent 和渲染狀態(tài)上下文 RenderErrorContext ,如果渲染插樁組件正常渲染,那么說明當(dāng)前組件沒有出現(xiàn)渲染異常,接下來需要在 useLayoutEffect 鉤子函數(shù)里面,上傳渲染成功狀態(tài)。

接下來看一下使用渲染上下文的頁面組件。

import React, { useEffect } from 'react'
import { RenderErrorContext } from './renderError'
import Comp from './component/comp1'

/* 模擬的渲染數(shù)據(jù) */
const renderList = [
  {
    id:1,
    data: {
      value:'我不是外星人'
    },
  },
  {
    id:2,
    data: {
      value:'大前端跨端開發(fā)指南'
    },
  },
  { /* 異常數(shù)據(jù) */
    id:3,
    data: null
  }

]

function App() {
  const [list,setList] = React.useState([])
  const renderState = React.useRef({
    errorList:[],
    setRenderKey(id){  //如果渲染成功了,那么將當(dāng)前 key 移除
      const index = renderState.current.errorList.indexOf(id) 
      renderState.current.errorList.splice(index,1)
    },
    getRenderKey(key){ //這里表示渲染了哪些組件
      renderState.current.errorList.push(key)
    }
  })
  useEffect(()=>{
      /* 記錄每一個(gè)待渲染的模版 */
      renderList.forEach(item => renderState.current.getRenderKey(item.id))
      setList(renderList)
      /*  驗(yàn)證模版是否正常渲染,如果 errorList 不為空,那么有渲染異常的組件,里面的 item 就是渲染異常的 id */
      setTimeout(()=>{
        console.log('errorList',renderState.current.errorList)
      })
  },[])
  return (
    <RenderErrorContext.Provider value={renderState.current}>
        { list.map(item=><Comp data={item.data} id={item.id}  key={item.id} />) }
    </RenderErrorContext.Provider>
  );
}
export default App;

如上就是頁面組件的使用,這里重點(diǎn)介紹一下每一個(gè)環(huán)節(jié):

  • 首先,用 ref 保存渲染狀態(tài) renderState,是一個(gè)對(duì)象,在對(duì)象里面一定要有 setRenderKey 方法,提供給插槽組件使用。最終將渲染狀態(tài)傳遞給 RenderErrorContext 的 Provider 中,接下來每一個(gè)需要監(jiān)控的下游組件都可以回傳渲染狀態(tài)了。
  • 在 useEffect 模擬請(qǐng)求數(shù)據(jù),然后根據(jù)數(shù)據(jù),記錄下來待渲染的 id,通過 getRenderKey 將 id 放入到數(shù)組中。
  • 接下來當(dāng)插樁組件正常渲染,那么會(huì)回傳狀態(tài),證明渲染成功了,那么將此渲染 id 從數(shù)組中移除。
  • 接下來用 setTimeout 驗(yàn)證模版是否正常渲染,如果 errorList 不為空,那么有渲染異常的組件,里面的 item 就是渲染異常的 id 。
  • 在渲染列表中,我們模擬一條異常數(shù)據(jù),就是第三條,data 為 null。

接下來看一下渲染插樁組件的使用:

import React from 'react'
import RenderErrorComponent from '../renderError'


function Comp({ data, id }){
    return <div>
         <div>{ data.value } </div>
        <RenderErrorComponent renderKey={id} />
    </div>
}

function ErrorHandle (Component){
    return class Wrap extends  React.Component{
        state = {
            isError:false
        }
        componentDidCatch(){
            this.setState({isError : true })
        }
        render(){
           const { isError } = this.state
           return  isError ? null : <Component {...this.props}  />
        }
    }
}

export default ErrorHandle(Comp) 

如上當(dāng)渲染 Comp 組件的時(shí)候,如果 data 為 null, 那么肯定會(huì)報(bào)出渲染異常,這個(gè)時(shí)候頁面都不會(huì)正常顯示,為了能夠讓頁面正常展示,我們用一個(gè)錯(cuò)誤處理組件 ErrorHandle 來防止白屏情況發(fā)生。

看一下效果:

如上頁面能夠正常渲染,從渲染異常列表里,能夠查詢到渲染異常的組件 id=3,預(yù)期達(dá)成。

四 總結(jié)

以上就是React捕獲并處理異常的方式的詳細(xì)內(nèi)容,更多關(guān)于React捕獲并處理異常的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 在react項(xiàng)目中webpack使用mock數(shù)據(jù)的操作方法

    在react項(xiàng)目中webpack使用mock數(shù)據(jù)的操作方法

    這篇文章主要介紹了在react項(xiàng)目中webpack使用mock數(shù)據(jù)的操作方法,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-06-06
  • 使用React和Redux Toolkit實(shí)現(xiàn)用戶登錄功能

    使用React和Redux Toolkit實(shí)現(xiàn)用戶登錄功能

    在React中,用戶登錄功能是一個(gè)常見的需求,為了實(shí)現(xiàn)該功能,需要對(duì)用戶輸入的用戶名和密碼進(jìn)行驗(yàn)證,并將驗(yàn)證結(jié)果保存到應(yīng)用程序狀態(tài)中,在React中,可以使用Redux Toolkit來管理應(yīng)用程序狀態(tài),從而實(shí)現(xiàn)用戶登錄功能,需要詳細(xì)了解可以參考下文
    2023-05-05
  • react:swr接口緩存案例代碼

    react:swr接口緩存案例代碼

    useSWR 是一個(gè) React Hooks,是 HTTP 緩存庫 SWR 的核心方法之一,SWR 是一個(gè)輕量級(jí)的 React Hooks 庫,通過自動(dòng)緩存數(shù)據(jù)來實(shí)現(xiàn) React 的數(shù)據(jù)獲取,本文給大家介紹react:swr接口緩存案例詳解,感興趣的朋友一起看看吧
    2023-11-11
  • 教你react中如何理解usestate、useEffect副作用、useRef標(biāo)識(shí)和useContext

    教你react中如何理解usestate、useEffect副作用、useRef標(biāo)識(shí)和useContext

    這篇文章主要介紹了react中如何理解usestate、useEffect副作用、useRef標(biāo)識(shí)和useContext,其實(shí)與vue中的ref和reactive一樣,通過useState獲取到的數(shù)據(jù)可以實(shí)現(xiàn)組件視圖實(shí)時(shí)交互,而普通定義的數(shù)據(jù)僅僅在業(yè)務(wù)中使用,需要的朋友可以參考下
    2022-11-11
  • react?hooks?UI與業(yè)務(wù)邏輯分離必要性技術(shù)方案

    react?hooks?UI與業(yè)務(wù)邏輯分離必要性技術(shù)方案

    這篇文章主要為大家介紹了react?hooks?UI與業(yè)務(wù)邏輯分離必要性技術(shù)方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • react中的ajax封裝實(shí)例詳解

    react中的ajax封裝實(shí)例詳解

    這篇文章主要介紹了react中的ajax封裝實(shí)例詳解的相關(guān)資料,希望通過本文能幫助到大家,讓大家理解掌握這部分內(nèi)容,需要的朋友可以參考下
    2017-10-10
  • 聊聊React onClick 傳遞參數(shù)的問題

    聊聊React onClick 傳遞參數(shù)的問題

    很多朋友向小編反映一個(gè)問題關(guān)于React onClick 傳遞參數(shù)的問題,當(dāng)點(diǎn)擊刪除按鈕需要執(zhí)行刪除操作,針對(duì)這個(gè)問題該如何處理呢?下面小編給大家?guī)砹薘eact onClick 傳遞參數(shù)的問題,感興趣的朋友一起看看吧
    2021-10-10
  • React中g(shù)etDefaultProps的使用小結(jié)

    React中g(shù)etDefaultProps的使用小結(jié)

    React中的getDefaultProps功能允許開發(fā)者為類組件定義默認(rèn)屬性,提高組件的靈活性和容錯(cuò)性,本文介紹了getDefaultProps的作用、語法以及最佳實(shí)踐,并探討了其他替代方案,如函數(shù)組件中的默認(rèn)參數(shù)、高階組件和ContextAPI等,理解這些概念有助于提升代碼的可維護(hù)性和用戶體驗(yàn)
    2024-09-09
  • React中使用axios發(fā)送請(qǐng)求的幾種常用方法

    React中使用axios發(fā)送請(qǐng)求的幾種常用方法

    本文主要介紹了React中使用axios發(fā)送請(qǐng)求的幾種常用方法,主要介紹了get和post請(qǐng)求,具有一定的參考價(jià)值,感興趣的可以了解一下
    2021-08-08
  • React實(shí)現(xiàn)全選功能

    React實(shí)現(xiàn)全選功能

    這篇文章主要為大家詳細(xì)介紹了React實(shí)現(xiàn)全選功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-08-08

最新評(píng)論