這是react16的內(nèi)容,并不是最新的技術(shù),但是用很少被討論,直到通過(guò)文檔發(fā)現(xiàn)其實(shí)也是很有用的一部分內(nèi)容,還是總結(jié)一下~
react中的未捕獲的 js 錯(cuò)誤會(huì)導(dǎo)致整個(gè)應(yīng)用的崩潰,和整個(gè)組件樹(shù)的卸載。從 react16 開(kāi)始就是這樣。但是同時(shí)react也引入了一個(gè)新的概念——錯(cuò)誤邊界。
定義,是什么
錯(cuò)誤邊界仍然是一種組件,可以捕獲(打印或者其他方式)處理該組件的子組件樹(shù)任何位置的 javascript 錯(cuò)誤,并根據(jù)需要渲染出備用ui.
工作方式類似于try-catch,但是錯(cuò)誤邊界只用于 react 組件。
只有class組件能夠成為錯(cuò)誤邊界組件。錯(cuò)誤邊界僅可以捕獲子組件的錯(cuò)誤,無(wú)法捕獲自身的錯(cuò)誤。
錯(cuò)誤邊界會(huì)在渲染期間,生命周期和整個(gè)組件樹(shù)的構(gòu)造函數(shù)中捕獲錯(cuò)誤。如果沒(méi)有錯(cuò)誤邊界處理,渲染的還是崩潰的子組件樹(shù),這顯然不是我們想要的。
通過(guò)一個(gè)例子來(lái)逐步演示要怎么用錯(cuò)誤邊界:
- export default class ErrorTest extends Component {
- constructor(props) {
- super(props);
- }
- render() {
- return (
- <div>
- <BugCounter></BugCounter>
- <span>my name is dan</span>
- </div>
- );
- }
- }
- // Bug 報(bào)錯(cuò)組件
- 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
,會(huì)逐步遞增。但是數(shù)字等于5
的時(shí)候,組件會(huì)拋出一個(gè)error
:
該error
會(huì)引起整個(gè)demo
的崩潰,連外部的<span>my name is dan</span>
也顯示不出來(lái)了,這時(shí)還沒(méi)有添加錯(cuò)誤邊界。
生產(chǎn)模式下,會(huì)直接白屏,并在控制臺(tái)報(bào)錯(cuò):
getderivedstatefromerror & componentdidcatch
需要一個(gè)錯(cuò)誤邊界來(lái)處理這種崩潰。如何定義一個(gè)錯(cuò)誤邊界?
定義一個(gè)組件,并實(shí)現(xiàn)static getderivedstatefromerror()
或者componentdidcatch()
生命周期方法(可以都實(shí)現(xiàn)或者選擇其一)。這個(gè)組件就會(huì)變成一個(gè)錯(cuò)誤邊界。
關(guān)于這兩個(gè)生命周期函數(shù),可以通過(guò)鏈接查看,總結(jié)如下:
- componentDidCatch(error, info)
error
是拋出的錯(cuò)誤對(duì)象,而info
則包含了組件引發(fā)錯(cuò)誤的棧信息。函數(shù)在提交階段被調(diào)用。是可以執(zhí)行副作用的。
- static getDerivedStateFromError(error)
在子組件拋出錯(cuò)誤后調(diào)用,會(huì)將拋出的錯(cuò)誤作為參數(shù)。需要返回一個(gè)值,以更新state。該函數(shù)在渲染階段調(diào)用,不允許出現(xiàn)副作用。如果在捕獲錯(cuò)誤后需要執(zhí)行副作用操作,應(yīng)該在componentdidcatch
中進(jìn)行。
制作錯(cuò)誤邊界組件
可以使用組合的方式,在要使用的組件上面添加一個(gè)錯(cuò)誤邊界組件包裹一層。該組件需要這些效果:
- 捕獲子組件錯(cuò)誤,組件內(nèi)部記錄出錯(cuò)狀態(tài)
- 在出錯(cuò)狀態(tài)下顯示備用ui,在正常狀態(tài)下顯示子組件
那么就可以像這樣:
- class ErrorBoundary extends React.Component {
- constructor(props) {
- super(props);
- this.state = { hasError: false };
- }
- static getDerivedStateFromError(error) {
- // 更新 state 使下一次渲染能夠顯示降級(jí)后的 UI
- return { hasError: true };
- }
- componentDidCatch(error, errorInfo) {
- // 你同樣可以將錯(cuò)誤日志上報(bào)給服務(wù)器
- logErrorToMyService(error, errorInfo);
- }
- render() {
- if (this.state.hasError) {
- // 你可以自定義降級(jí)后的 UI 并渲染
- return <h1>Something went wrong.</h1>;
- }
- return this.props.children;
- }
- }
捕獲到錯(cuò)誤之后的副作用是自定義的,上傳服務(wù)器,或者用state
記錄再顯示在頁(yè)面上:
- componentDidCatch(error, errorInfo) {
- // Catch errors in any components below and re-render with error message
- this.setState({
- error: error,
- errorInfo: errorInfo
- })
- }
捕獲處理
加上所有代碼,將有問(wèn)題的組件用錯(cuò)誤邊界的組件包裹起來(lái),看看結(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 報(bào)錯(cuò)組件
- 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>
- );
- }
- }
- // 錯(cuò)誤邊界處理組件
- class ErrorBoundary extends Component {
- constructor(props) {
- super(props);
- this.state = { hasError: false };
- }
- static getDerivedStateFromError(error) {
- // 更新 state 使下一次渲染能夠顯示降級(jí)后的 UI
- return { hasError: true };
- }
- render() {
- if (this.state.hasError) {
- // 你可以自定義降級(jí)后的 UI 并渲染
- return <h1>Something went wrong.</h1>;
- }
- return this.props.children;
- }
- }
拋出異常在開(kāi)發(fā)模式下依然是報(bào)錯(cuò)的,但是在使用yarn build
之后,再通過(guò)http-server
掛起來(lái)之后,訪問(wèn)生產(chǎn)的頁(yè)面:
可以看到,雖然因?yàn)?code>throw error控制臺(tái)出錯(cuò),但是my name is dan
的顯示并沒(méi)有被影響,也就是說(shuō),錯(cuò)誤邊界內(nèi)部的子組件錯(cuò)誤沒(méi)有影響到外部其他組件和元素。
作用范圍
錯(cuò)誤邊界用于處理子組件生命周期和渲染函數(shù)上的錯(cuò)誤,對(duì)于事件處理器,不會(huì)在渲染期間觸發(fā),對(duì)于事件處理器拋出的異常應(yīng)該用try catch
。
錯(cuò)誤邊界無(wú)法捕獲這些場(chǎng)景中的錯(cuò)誤:
- 事件處理
- 異步代碼
- 服務(wù)端渲染
- 錯(cuò)誤邊界自身拋出的錯(cuò)誤(非子組件)
關(guān)于錯(cuò)誤邊界,一個(gè) 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 錯(cuò)誤邊界組件的處理的文章就介紹到這了,更多相關(guān)react 錯(cuò)誤邊界內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://www.cnblogs.com/xuxiaowei/p/14645136.html