React 錯誤邊界組件的處理
這是React16的內(nèi)容,并不是最新的技術(shù),但是用很少被討論,直到通過文檔發(fā)現(xiàn)其實(shí)也是很有用的一部分內(nèi)容,還是總結(jié)一下~
React中的未捕獲的 JS 錯誤會導(dǎo)致整個應(yīng)用的崩潰,和整個組件樹的卸載。從 React16 開始就是這樣。但是同時React也引入了一個新的概念——錯誤邊界。
定義,是什么
錯誤邊界仍然是一種組件,可以捕獲(打印或者其他方式)處理該組件的子組件樹任何位置的 JavaScript 錯誤,并根據(jù)需要渲染出備用UI.
工作方式類似于try-catch,但是錯誤邊界只用于 React 組件。
只有class組件能夠成為錯誤邊界組件。錯誤邊界僅可以捕獲子組件的錯誤,無法捕獲自身的錯誤。
錯誤邊界會在渲染期間,生命周期和整個組件樹的構(gòu)造函數(shù)中捕獲錯誤。如果沒有錯誤邊界處理,渲染的還是崩潰的子組件樹,這顯然不是我們想要的。
通過一個例子來逐步演示要怎么用錯誤邊界:
export default class ErrorTest extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<BugCounter></BugCounter>
<span>my name is dan</span>
</div>
);
}
}
// Bug 報錯組件
class BugCounter extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0,
};
}
click = () => {
this.setState(({ counter }) => ({ counter: counter + 1 }));
};
render() {
if (this.state.counter === 5) {
throw new Error("crashed!");
}
return (
<div>
<h3 onClick={this.click}>{this.state.counter}</h3>
</div>
);
}
}
上面代碼的渲染結(jié)果(忽略樣式):

點(diǎn)擊數(shù)字0,會逐步遞增。但是數(shù)字等于5的時候,組件會拋出一個Error:

該Error會引起整個Demo的崩潰,連外部的<span>my name is dan</span>也顯示不出來了,這時還沒有添加錯誤邊界。
生產(chǎn)模式下,會直接白屏,并在控制臺報錯:

getDerivedStateFromError & componentDidCatch
需要一個錯誤邊界來處理這種崩潰。如何定義一個錯誤邊界?
定義一個組件,并實(shí)現(xiàn)static getDerivedStateFromError() 或者componentDidCatch() 生命周期方法(可以都實(shí)現(xiàn)或者選擇其一)。這個組件就會變成一個錯誤邊界。
關(guān)于這兩個生命周期函數(shù),可以通過鏈接查看,總結(jié)如下:
componentDidCatch(error, info)
error是拋出的錯誤對象,而info則包含了組件引發(fā)錯誤的棧信息。函數(shù)在提交階段被調(diào)用。是可以執(zhí)行副作用的。
static getDerivedStateFromError(error)
在子組件拋出錯誤后調(diào)用,會將拋出的錯誤作為參數(shù)。需要返回一個值,以更新state。該函數(shù)在渲染階段調(diào)用,不允許出現(xiàn)副作用。如果在捕獲錯誤后需要執(zhí)行副作用操作,應(yīng)該在componentDidCatch中進(jìn)行。
制作錯誤邊界組件
可以使用組合的方式,在要使用的組件上面添加一個錯誤邊界組件包裹一層。該組件需要這些效果:
- 捕獲子組件錯誤,組件內(nèi)部記錄出錯狀態(tài)
- 在出錯狀態(tài)下顯示備用UI,在正常狀態(tài)下顯示子組件
那么就可以像這樣:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染能夠顯示降級后的 UI
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// 你同樣可以將錯誤日志上報給服務(wù)器
logErrorToMyService(error, errorInfo);
}
render() {
if (this.state.hasError) {
// 你可以自定義降級后的 UI 并渲染
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
捕獲到錯誤之后的副作用是自定義的,上傳服務(wù)器,或者用state記錄再顯示在頁面上:
componentDidCatch(error, errorInfo) {
// Catch errors in any components below and re-render with error message
this.setState({
error: error,
errorInfo: errorInfo
})
}
捕獲處理
加上所有代碼,將有問題的組件用錯誤邊界的組件包裹起來,看看結(jié)果:
import { Component } from "react";
export default class ErrorTest extends Component {
render() {
return (
<div>
<ErrorBoundary>
<BugCounter></BugCounter>
</ErrorBoundary>
<span>my name is dan</span>
</div>
);
}
}
// Bug 報錯組件
class BugCounter extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0,
};
}
click = () => {
this.setState(({ counter }) => ({ counter: counter + 1 }));
};
render() {
if (this.state.counter === 5) {
throw new Error("crashed!");
}
return (
<div>
<h3 onClick={this.click}>{this.state.counter}</h3>
</div>
);
}
}
// 錯誤邊界處理組件
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染能夠顯示降級后的 UI
return { hasError: true };
}
render() {
if (this.state.hasError) {
// 你可以自定義降級后的 UI 并渲染
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
拋出異常在開發(fā)模式下依然是報錯的,但是在使用yarn build之后,再通過http-server掛起來之后,訪問生產(chǎn)的頁面:

可以看到,雖然因?yàn)?code>throw error控制臺出錯,但是my name is dan的顯示并沒有被影響,也就是說,錯誤邊界內(nèi)部的子組件錯誤沒有影響到外部其他組件和元素。
作用范圍
錯誤邊界用于處理子組件生命周期和渲染函數(shù)上的錯誤,對于事件處理器,不會在渲染期間觸發(fā),對于事件處理器拋出的異常應(yīng)該用try catch。
錯誤邊界無法捕獲這些場景中的錯誤:
- 事件處理
- 異步代碼
- 服務(wù)端渲染
- 錯誤邊界自身拋出的錯誤(非子組件)
關(guān)于錯誤邊界,一個 React的官方demo值得嘗試:
https://codepen.io/gaearon/pen/wqvxGa?editors=0010
參考:
https://zh-hans.reactjs.org/docs/error-boundaries.html
https://zh-hans.reactjs.org/docs/react-component.html
https://codepen.io/gaearon/pen/wqvxGa?editors=0010
到此這篇關(guān)于React 錯誤邊界組件的處理的文章就介紹到這了,更多相關(guān)React 錯誤邊界內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ReactNative之鍵盤Keyboard的彈出與消失示例
本篇文章主要介紹了ReactNative之鍵盤Keyboard的彈出與消失示例,具有一定的參考價值,有興趣的可以了解一下2017-07-07
React?Hooks使用startTransition與useTransition教程示例
這篇文章主要為大家介紹了React?Hooks使用startTransition與useTransition教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
React?高階組件與Render?Props優(yōu)缺點(diǎn)詳解
這篇文章主要weidajai?介紹了React?高階組件與Render?Props優(yōu)缺點(diǎn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
React Hook 父子組件相互調(diào)用函數(shù)方式
這篇文章主要介紹了React Hook 父子組件相互調(diào)用函數(shù)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09
React-Hooks之useImperativeHandler使用介紹
這篇文章主要為大家介紹了React-Hooks之useImperativeHandler使用介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
React使用context進(jìn)行跨級組件數(shù)據(jù)傳遞
這篇文章給大家介紹了React使用context進(jìn)行跨級組件數(shù)據(jù)傳遞的方法步驟,文中通過代碼示例給大家介紹的非常詳細(xì),對大家學(xué)習(xí)React context組件數(shù)據(jù)傳遞有一定的幫助,感興趣的小伙伴跟著小編一起來學(xué)習(xí)吧2024-01-01

