React 捕捉錯誤|使用原生函式 componentDidCatch + Error Boundaries 來捕捉元件錯誤。

Use React componentDidCatch and Error Boundaries to catch components’ error!

Molly Chi
6 min readNov 2, 2022

|前言

本篇將整理 componentDidCatch + Error Boundaries 捕捉錯誤的基本觀念及實作。(讀了官網及10篇以上的相關文章及 stackoverflow,可信度應該算高啦)

最近因為工作不得不看前人們的 code,發現大部分都以新版 react hooks 做撰寫,但發現在抓 error 的時候,會使用 class 來寫,於是乎研究了一下,發現好像很好用,以後的專案應該都會加入這格式,抓錯有點太方便啊~~~~~。

|基本觀念

  1. 當子元件發生錯誤時就會被 Error Boundary 捕捉,不會讓錯誤影響到錯誤邊界外的任何元件。
  2. 目前沒有任何 React 原生的 hooks 能取代 componentDidCatch。(Only class components can be error boundaries.)
  3. Error Boundaries(錯誤邊界)不會捕獲以下錯誤:
  • 事件處理程序 (event handler)
  • 異步(非同步)代碼(例如 setTimeout)
  • 服務器端渲染
  • 在錯誤邊界本身(而不是其子項)中引發的錯誤

|跟 try catch 差在哪裡

try catch 只適用於命令式代碼 (imperative code),而 React 元件是聲明式 (declarative code),所以不能用 try catch 取代。

但處理事件還是要用 try catch,因為他 (event handlers) 不是發生在渲染期間的事情。

https://reactjs.org/docs/error-boundaries.html

|官網範例

點擊數字至5,就會發生 error,上面的 <BuggyCounter /> 包在同一個 <ErrorBoundary> 內,所以只要有一個錯,整個元件都會被刪除;下方的是個別包在 <ErrorBoundary>,故錯誤邊界只在各自的元件中。

code:

|如何自製一個捕捉錯誤元件

  1. 假設我們有一個元件 Box,裡面的按鈕點下去,元件就會錯誤
const Box = () => {
const [state, setState] = useState(true);
const handleChange = () => {
setState(!state);
};
if (!state) {
throw new Error("I crashed!");
}
return (
<div>
<h1>Hello</h1>
<button
onClick={() => {
handleChange();
}}
>
click
</button>
</div>
);
};

2. 為了不讓整個頁面都壞掉,我們幫元件加上 ErrorBoundary,ErrorBoundary 寫法跟官網提供的一樣

class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { error: null, errorInfo: null };
}

componentDidCatch(error, errorInfo) {
// Catch errors in any components below and re-render with error message
this.setState({
error: error,
errorInfo: errorInfo
})
// You can also log error messages to an error reporting service here
}

render() {
if (this.state.errorInfo) {
// Error path
return (
<div>
<h2>Something went wrong.</h2>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.error && this.state.error.toString()}
<br />
{this.state.errorInfo.componentStack}
</details>
</div>
);
}
// Normally, just render children
return this.props.children;
}
}

3. 包進去!

function App() {
return (
<div>
<p>BOX沒有包在 ErrorBoundary</p>
<Box />
<hr />
<p>兩個BOX包在同一個 ErrorBoundary</p>
<ErrorBoundary>
<Box />
<Box />
</ErrorBoundary>
<hr />
<p>兩個BOX分別在 ErrorBoundary</p>
<ErrorBoundary>
<Box />
</ErrorBoundary>
<ErrorBoundary>
<Box />
</ErrorBoundary>
</div>
);
}

4. 可以看到在第一個 Box ,沒有包在 ErrorBoundary 錯誤邊界中,點下去後整個頁面都消失了。

5. 而有包在 ErrorBoundary 的元件,發生錯誤時不會影響其他元件。

完整 code:

|總結

相見恨晚 (๑´ڡ`๑)~~

--

--

Molly Chi
Molly Chi

Written by Molly Chi

Software Developer / 職稱是軟體研發工程師。 什麼都寫,專精於前端及APP (ง•̀_•́)ง ! ❤ 合作發案討論疑難雜症請洽: momolly1024@gmail.com

No responses yet