React中Portals與錯誤邊界處理實現
Portals
可以說是 插槽,但 不同於 Vue 中的 slot,它指的是將一個 React 元素渲染到指定的容器 (真實 DOM) 中
比如說,Modal 組件一般默認直接作為 body 的真實結構的子元素渲染出來,那麼我們就可以借助 ReactDOM.createPortal(ReactElement, RealDOM container) 創建一個 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> }
我們可以在瀏覽器控制臺中看到,真實的 Modal 組件其實是作為 body 的直接子元素渲染出來的,但通過 React 開發者工具,我們可以看到 Modal 組件在虛擬 DOM 樹的結構中依舊在 App 組件下,類名為 app-container 的 div 中
所以,我們可以得出結論:React 組件虛擬 DOM 樹結構與真實 DOM 樹結構可以是不一致的
因而需要註意事件冒泡
- React 中的事件其實是經過包裝的
- 它的事件冒泡是根據虛擬 DOM 樹的結構來冒泡的,而不是真實 DOM 樹的冒泡機制
錯誤邊界處理
默認情況下,若一個組件在渲染期間 (render) 發生錯誤,那麼就會導致整個組件樹全部被卸載
錯誤邊界:就是一個組件,用於捕獲 渲染期間 子組件發生的錯誤,並有能力阻止錯誤繼續向父組件傳播
讓某個組件捕獲錯誤 (類組件):
使用靜態方法 static getDerivedStateFromError,子組件渲染錯誤時會觸發此函數
- 靜態方法,所以不能使用 this
- 此函數返回值 (對象) 會與 state 混合覆蓋狀態
- 觸發時間點為:渲染子組件發生錯誤後,在更新頁面之前
- 隻有子組件渲染發生錯誤,才會觸發 (即自身組件發生錯誤或其兄弟組件、父組件發生錯誤均不會觸發)
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) 函數
- 是個實例方法
- 運行時機在渲染子組件發生錯誤後,且頁面更新之後 (更改狀態會導致組件樹卸載完之後又重新構建組件樹,比較浪費效率)
- 通常該函數用於往後臺傳遞並記錄錯誤信息
import React, {PureComponent} from 'react' export default class ErrorBoundary extends PureComponent { state = { isError: false } componentDidCatch(error, info) { // info 即為錯誤的摘要信息 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 } }
如果沒有使用錯誤邊界會怎樣?
自 React 16 起,任何未被錯誤邊界捕獲的錯誤將會導致整個 React 組件樹被卸載。
經驗告訴我們,完全移除比保留錯誤UI更好。例如,在類似 Messenger 的產品中,把異常的 UI 展示給用戶可能會導致用戶將信息錯發給別人。
增加錯誤邊界能夠讓你在應用發生異常時提供更好的用戶體驗。例如,Facebook Messenger 將側邊欄、信息面板、聊天記錄以及信息輸入框包裝在單獨的錯誤邊界中。如果其中的某些 UI 組件崩潰,其餘部分仍然能夠交互。
註意點
某些錯誤,錯誤邊界組件不會捕獲
自身組件的錯誤
異步的錯誤 (如 setTimeout 中拋出的錯誤)
import React, {PureComponent} from 'react' // ErrorBoundary.jsx 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 } } // 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> </> }
事件中拋出的錯誤
即:僅處理渲染子組件期間的同步錯誤
到此這篇關於React中Portals與錯誤邊界處理實現的文章就介紹到這瞭,更多相關React Portals與錯誤邊界處理內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- react進階教程之異常處理機制error Boundaries
- React 性能優化之非必要的渲染問題解決
- 提高React界面性能的十個技巧
- 詳解React獲取DOM和獲取組件實例的方式
- 可定制react18 input otp 一次性密碼輸入組件