面試官:說說你在React項目是如何捕獲錯誤的?
本文轉載自微信公眾號「JS每日一題」,作者灰灰。轉載本文請聯系JS每日一題公眾號。
一、是什么
錯誤在我們日常編寫代碼是非常常見的
舉個例子,在react項目中去編寫組件內JavaScript代碼錯誤會導致 React 的內部狀態被破壞,導致整個應用崩潰,這是不應該出現的現象
作為一個框架,react也有自身對于錯誤的處理的解決方案
二、如何做
為了解決出現的錯誤導致整個應用崩潰的問題,react16引用了「錯誤邊界」新的概念
錯誤邊界是一種 React 組件,這種組件可以捕獲發生在其子組件樹任何位置的 JavaScript 錯誤,并打印這些錯誤,同時展示降級 UI,而并不會渲染那些發生崩潰的子組件樹
錯誤邊界在渲染期間、生命周期方法和整個組件樹的構造函數中捕獲錯誤
形成錯誤邊界組件的兩個條件:
- 使用了 static getDerivedStateFromError()
- 使用了 componentDidCatch()
拋出錯誤后,請使用 static getDerivedStateFromError() 渲染備用 UI ,使用 componentDidCatch() 打印錯誤信息,如下:
- class ErrorBoundary extends React.Component {
- constructor(props) {
- super(props);
- this.state = { hasError: false };
- }
- static getDerivedStateFromError(error) {
- // 更新 state 使下一次渲染能夠顯示降級后的 UI
- return { hasError: true };
- }
- componentDidCatch(error, errorInfo) {
- // 你同樣可以將錯誤日志上報給服務器
- logErrorToMyService(error, errorInfo);
- }
- render() {
- if (this.state.hasError) {
- // 你可以自定義降級后的 UI 并渲染
- return <h1>Something went wrong.</h1>;
- }
- return this.props.children;
- }
- }
然后就可以把自身組件的作為錯誤邊界的子組件,如下:
- <ErrorBoundary>
- <MyWidget />
- </ErrorBoundary>
下面這些情況無法捕獲到異常:
- 事件處理
- 異步代碼
- 服務端渲染
- 自身拋出來的錯誤
在react 16版本之后,會把渲染期間發生的所有錯誤打印到控制臺
除了錯誤信息和 JavaScript 棧外,React 16 還提供了組件棧追蹤。現在你可以準確地查看發生在組件樹內的錯誤信息:
可以看到在錯誤信息下方文字中存在一個組件棧,便于我們追蹤錯誤
對于錯誤邊界無法捕獲的異常,如事件處理過程中發生問題并不會捕獲到,是因為其不會在渲染期間觸發,并不會導致渲染時候問題
這種情況可以使用js的try...catch...語法,如下:
- class MyComponent extends React.Component {
- constructor(props) {
- super(props);
- this.state = { error: null };
- this.handleClick = this.handleClick.bind(this);
- }
- handleClick() {
- try {
- // 執行操作,如有錯誤則會拋出
- } catch (error) {
- this.setState({ error });
- }
- }
- render() {
- if (this.state.error) {
- return <h1>Caught an error.</h1>
- }
- return <button onClick={this.handleClick}>Click Me</button>
- }
- }
除此之外還可以通過監聽onerror事件
- window.addEventListener('error', function(event) { ... })
參考文獻
https://zh-hans.reactjs.org/docs/error-boundaries.html