UI的某一部分拋錯不該該致使整個App都崩掉,React 16由此提出一個新概念叫「error boundary」,錯誤邊界html
「error boundary」是什麼呢,是一個React組件。error boundary能捕獲子組件樹中發生的任何錯誤,而後打日誌,返回fallback UI。react
error boundary能捕獲哪兒的錯誤:git
error boundary不能捕獲哪兒的錯誤:github
setTimeout
or requestAnimationFrame
callbacks)若是一個組件定義了static getDerivedStateFromError()或componentDidCatch()或兩個都有,那麼這個組件就是一個error boundary。npm
static getDerivedStateFromError()用於拋錯後返回fallback UI,componentDidCatch()用於打錯誤日誌瀏覽器
下面舉個例子babel
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}
componentDidCatch(error, info) {
// You can also log the error to an error reporting service
logErrorToMyService(error, info);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
複製代碼
而後就能把組件在ErrorBoundary裏就能夠了app
<ErrorBoundary>
<MyWidget /> </ErrorBoundary>
複製代碼
ErrorBoundary至關於組件的catch{}塊。只要class型的組件能用ErrorBoundary,function型的不能用。異步
一般實踐推薦在App裏一處定義,到處使用ide
注意,ErrorBoundary只catch它子組件的錯,它自個兒的錯不catch。固然了,若是ErrorBoundary拋錯了那它會傳到它上面的ErrorBoundary去處理。
Check out this example of declaring and using an error boundary with React 16.
隨便,看你怎麼寫。包裹整個APP也成,包裹一個小組件也成
這個變化意義重大。對於React 16來講,未被Error Boundaries捕獲的錯誤會 unmount 整個react組件樹
爲啥這麼作呢?React的人認爲,寧肯我給整個APP都掛掉也比返一個部分掛掉的UI強。比方說通訊類app,一個掛掉的UI可能致使信息發錯人;再比方說支付類APP,顯示錯誤的帳戶餘額還不如啥都不顯示
多用Error Boundaries更帶來更好的用戶體驗。Facebook Messenger 給sidebar,info panel,conversation log都各自包了一層ErrorBoundary,這樣某個組件掛了不會影響其餘的,並且能展現不一樣的fallback UI
推薦你用一些JS錯誤彙報工具
Create React App默認配置的,若是沒用要加 this plugin到babel。
開發環境使用,生產環境禁用!
組件堆棧跟蹤的組件名是調Function.name
獲得的,低版本瀏覽器本身polyfill
try/catch只適用於當即執行的代碼
try {
showButton();
} catch (error) {
// ...
}
複製代碼
可是react組件是聲明式的,說明將要渲染什麼,Error boundaries保留了react聲明式的特色
blabalbla...
Error boundaries do not catch errors inside event handlers!
渲染的時候不會處理事件的,因此事件處理程序拋錯react會知道的。
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { error: null };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
try {
// Do something that could throw
} catch (error) {
this.setState({ error });
}
}
render() {
if (this.state.error) {
return <h1>Caught an error.</h1>
}
return <div onClick={this.handleClick}>Click Me</div>
}
}
複製代碼
unstable_handleError 改爲了 componentDidCatch
這部分變化codemod能夠幫你自動遷移代碼