欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React捕獲并處理異常的方式

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

一 前言

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

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

在 React 中,出現(xià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>
} 

如上,在第三個 Comp 組件渲染的時候,因為 data 傳入的值是 null ,而在渲染階段讀取了 data 下面的屬性,這個時候就會報空指針的錯誤:Cannot read properties of null ,結(jié)果就是整個頁面都白屏。

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

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

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

那么如何處理這個問題呢?

二 渲染異常處理

componentDidCatch

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

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

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

那么 componentDidCatch 中可以再次觸發(fā) setState,來降級 UI 渲染,componentDidCatch 會在 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)生的影響,由頁面維護,降低到了組件維度。其他部分的視圖也能夠正常渲染了。

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

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

HOC 助力渲染異常組件

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

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

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

渲染插槽+context上下文

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

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

原理圖:

介紹完原理來看一下代碼的實現(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(()=>{
        /* 渲染正常,上報渲染 key */
        setRenderKey && setRenderKey(renderKey)
    },[])
    return <React.Fragment />
}

如上編寫的渲染插樁組件 RenderErrorComponent 和渲染狀態(tài)上下文 RenderErrorContext ,如果渲染插樁組件正常渲染,那么說明當前組件沒有出現(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){  //如果渲染成功了,那么將當前 key 移除
      const index = renderState.current.errorList.indexOf(id) 
      renderState.current.errorList.splice(index,1)
    },
    getRenderKey(key){ //這里表示渲染了哪些組件
      renderState.current.errorList.push(key)
    }
  })
  useEffect(()=>{
      /* 記錄每一個待渲染的模版 */
      renderList.forEach(item => renderState.current.getRenderKey(item.id))
      setList(renderList)
      /*  驗證模版是否正常渲染,如果 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;

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

  • 首先,用 ref 保存渲染狀態(tài) renderState,是一個對象,在對象里面一定要有 setRenderKey 方法,提供給插槽組件使用。最終將渲染狀態(tài)傳遞給 RenderErrorContext 的 Provider 中,接下來每一個需要監(jiān)控的下游組件都可以回傳渲染狀態(tài)了。
  • 在 useEffect 模擬請求數(shù)據(jù),然后根據(jù)數(shù)據(jù),記錄下來待渲染的 id,通過 getRenderKey 將 id 放入到數(shù)組中。
  • 接下來當插樁組件正常渲染,那么會回傳狀態(tài),證明渲染成功了,那么將此渲染 id 從數(shù)組中移除。
  • 接下來用 setTimeout 驗證模版是否正常渲染,如果 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) 

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

看一下效果:

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

四 總結(jié)

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

相關(guān)文章

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

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

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

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

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

    react:swr接口緩存案例代碼

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

    教你react中如何理解usestate、useEffect副作用、useRef標識和useContext

    這篇文章主要介紹了react中如何理解usestate、useEffect副作用、useRef標識和useContext,其實與vue中的ref和reactive一樣,通過useState獲取到的數(shù)據(jù)可以實現(xiàn)組件視圖實時交互,而普通定義的數(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ù)方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • react中的ajax封裝實例詳解

    react中的ajax封裝實例詳解

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

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

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

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

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

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

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

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

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

最新評論