React中Portals與錯(cuò)誤邊界處理實(shí)現(xiàn)
Portals
可以說(shuō)是 插槽,但 不同于 Vue 中的 slot,它指的是將一個(gè) React 元素渲染到指定的容器 (真實(shí) DOM) 中
比如說(shuō),Modal 組件一般默認(rèn)直接作為 body 的真實(shí)結(jié)構(gòu)的子元素渲染出來(lái),那么我們就可以借助 ReactDOM.createPortal(ReactElement, RealDOM container) 創(chuàng)建一個(gè) React 元素,示例代碼:
import React from 'react'
import ReactDOM from 'react-dom'
import Modal from './components/Modal'
const PortalModal = ReactDOM.createPortal(<Modal />, document.body)
export default function App() {
return <div className="app-container">
<PortalModal />
</div>
}
我們可以在瀏覽器控制臺(tái)中看到,真實(shí)的 Modal 組件其實(shí)是作為 body 的直接子元素渲染出來(lái)的,但通過(guò) React 開(kāi)發(fā)者工具,我們可以看到 Modal 組件在虛擬 DOM 樹(shù)的結(jié)構(gòu)中依舊在 App 組件下,類名為 app-container 的 div 中
所以,我們可以得出結(jié)論:React 組件虛擬 DOM 樹(shù)結(jié)構(gòu)與真實(shí) DOM 樹(shù)結(jié)構(gòu)可以是不一致的
因而需要注意事件冒泡
- React 中的事件其實(shí)是經(jīng)過(guò)包裝的
- 它的事件冒泡是根據(jù)虛擬 DOM 樹(shù)的結(jié)構(gòu)來(lái)冒泡的,而不是真實(shí) DOM 樹(shù)的冒泡機(jī)制
錯(cuò)誤邊界處理
默認(rèn)情況下,若一個(gè)組件在渲染期間 (render) 發(fā)生錯(cuò)誤,那么就會(huì)導(dǎo)致整個(gè)組件樹(shù)全部被卸載
錯(cuò)誤邊界:就是一個(gè)組件,用于捕獲 渲染期間 子組件發(fā)生的錯(cuò)誤,并有能力阻止錯(cuò)誤繼續(xù)向父組件傳播
讓某個(gè)組件捕獲錯(cuò)誤 (類組件):
使用靜態(tài)方法 static getDerivedStateFromError,子組件渲染錯(cuò)誤時(shí)會(huì)觸發(fā)此函數(shù)
- 靜態(tài)方法,所以不能使用 this
- 此函數(shù)返回值 (對(duì)象) 會(huì)與 state 混合覆蓋狀態(tài)
- 觸發(fā)時(shí)間點(diǎn)為:渲染子組件發(fā)生錯(cuò)誤后,在更新頁(yè)面之前
- 只有子組件渲染發(fā)生錯(cuò)誤,才會(huì)觸發(fā) (即自身組件發(fā)生錯(cuò)誤或其兄弟組件、父組件發(fā)生錯(cuò)誤均不會(huì)觸發(fā))
import React, {PureComponent} from 'react'
export default class ErrorBoundary extends PureComponent {
state = {
isError: false
}
static getDerivedStateFromError(error) {
console.log('Rendering Error: ', error)
return {
isError: true
}
}
render() {
if (this.isError) {
return <span>Something Wrong...</span>
}
return this.props.children
}
}
使用 componentDidCatch(error, info) 函數(shù)
- 是個(gè)實(shí)例方法
- 運(yùn)行時(shí)機(jī)在渲染子組件發(fā)生錯(cuò)誤后,且頁(yè)面更新之后 (更改狀態(tài)會(huì)導(dǎo)致組件樹(shù)卸載完之后又重新構(gòu)建組件樹(shù),比較浪費(fèi)效率)
- 通常該函數(shù)用于往后臺(tái)傳遞并記錄錯(cuò)誤信息
import React, {PureComponent} from 'react'
export default class ErrorBoundary extends PureComponent {
state = {
isError: false
}
componentDidCatch(error, info) {
// info 即為錯(cuò)誤的摘要信息
console.log('Rendering Error: ', error)
console.log('Rendering info: ', info)
this.setState({
isError: true
})
}
render() {
if (this.isError) {
return <span>Something Wrong...</span>
}
return this.props.children
}
}
如果沒(méi)有使用錯(cuò)誤邊界會(huì)怎樣?
自 React 16 起,任何未被錯(cuò)誤邊界捕獲的錯(cuò)誤將會(huì)導(dǎo)致整個(gè) React 組件樹(shù)被卸載。
經(jīng)驗(yàn)告訴我們,完全移除比保留錯(cuò)誤UI更好。例如,在類似 Messenger 的產(chǎn)品中,把異常的 UI 展示給用戶可能會(huì)導(dǎo)致用戶將信息錯(cuò)發(fā)給別人。
增加錯(cuò)誤邊界能夠讓你在應(yīng)用發(fā)生異常時(shí)提供更好的用戶體驗(yàn)。例如,F(xiàn)acebook Messenger 將側(cè)邊欄、信息面板、聊天記錄以及信息輸入框包裝在單獨(dú)的錯(cuò)誤邊界中。如果其中的某些 UI 組件崩潰,其余部分仍然能夠交互。
注意點(diǎn)
某些錯(cuò)誤,錯(cuò)誤邊界組件不會(huì)捕獲
自身組件的錯(cuò)誤
異步的錯(cuò)誤 (如 setTimeout 中拋出的錯(cuò)誤)
import React, {PureComponent} from 'react'
// ErrorBoundary.jsx
export default class ErrorBoundary extends PureComponent {
state = {
isError: false
}
/* 此函數(shù)不會(huì)運(yùn)行 */
static getDerivedStateFromError(error) {
console.log('Rendering Error: ', error)
return {
isError: true
}
}
render() {
if (this.isError) {
return <span>Something Wrong...</span>
}
return this.props.children
}
}
// Comp.jsx Comp 組件
export default funtion Comp() {
setTimeout(() => {
throw new Error('setTimeout error')
}, 1000)
return <div>Comp</div>
}
// App.jsx 使用
export default function App() {
return <>
<ErrorBoundary>
<Comp />
</ErrorBoundary>
</>
}
事件中拋出的錯(cuò)誤
即:僅處理渲染子組件期間的同步錯(cuò)誤
到此這篇關(guān)于React中Portals與錯(cuò)誤邊界處理實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)React Portals與錯(cuò)誤邊界處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解關(guān)于react-redux中的connect用法介紹及原理解析
本篇文章主要介紹了詳解關(guān)于react-redux中的connect用法介紹及原理解析,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-09-09
使用React實(shí)現(xiàn)一個(gè)簡(jiǎn)單的待辦事項(xiàng)列表的示例代碼
這篇文章我們將詳細(xì)講解如何建立一個(gè)這樣簡(jiǎn)單的列表,文章通過(guò)代碼示例介紹的非常詳細(xì),對(duì)我們的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2023-08-08
React實(shí)現(xiàn)虛擬滾動(dòng)的三種思路詳解
在??web??開(kāi)發(fā)的過(guò)程中,或多或少都會(huì)遇到大列表渲染的場(chǎng)景,為了解決大列表造成的渲染壓力,便出現(xiàn)了虛擬滾動(dòng)技術(shù),本文主要介紹虛擬滾動(dòng)的三種思路,希望對(duì)大家有所幫助2024-04-04
利用React高階組件實(shí)現(xiàn)一個(gè)面包屑導(dǎo)航的示例
這篇文章主要介紹了利用React高階組件實(shí)現(xiàn)一個(gè)面包屑導(dǎo)航的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
淺談React + Webpack 構(gòu)建打包優(yōu)化
本篇文章主要介紹了淺談React + Webpack 構(gòu)建打包優(yōu)化,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
React不能將useMemo設(shè)置為默認(rèn)方法原因詳解
這篇文章主要為大家介紹了React不能將useMemo設(shè)置為默認(rèn)方法原因詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪<BR>2022-07-07
解決React報(bào)錯(cuò)`value` prop on `input` should&
這篇文章主要為大家介紹了React報(bào)錯(cuò)`value` prop on `input` should not be null解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12

