[譯]React高階話題之Error Boundaries
本文為意譯,翻譯過程中摻雜本人的理解,如有誤導,請放棄繼續閱讀。
原文地址:Error Boundaries
在過去,React元件內部的javascript錯誤往往會讓React內部的state變得不可用,並且會在下一次的渲染過程中產生模稜兩可的錯誤資訊。這些錯誤常常是由應用先前的錯誤所引起的,但是React並沒有提供一個優雅的方案去在元件內部處理這種錯誤,並將應用恢復到正常的狀態。
正文
介紹Error Boundaries
應用中區域性UI中的javascript錯誤按理說不應該導致整個應用都崩潰掉。為了幫助React使用者解決這種問題,React在16.x.x中引入了新的概念-“error boundary”。
什麼是“error boundary”呢?“error boundary”就是一種能夠捕獲它的子元件樹所產生的錯誤的React元件
。在這種元件裡,你能夠把這些錯誤日誌打印出來,又或者相比簡單粗暴地把元件樹崩潰後的介面呈現給使用者,你可以呈現一個精心設計過的備用介面給使用者(為了強調error boundary是一個元件,我後面的翻譯過程中使用<Error boundary>
來指代)。<Error boundary>
能捕獲在渲染過程中,所有子元件的constructors和生命週期函式裡面發生的錯誤。
<Error boundary>
不能捕獲以下型別的錯誤:
<Error boundary>
從程式碼的層面來說,只要一個class component定義了static getDerivedStateFromError()
和componentDidCatch()
方法中的一個,又或者兩個都定義了,我們就說它是一個<Error boundary>
。上面提到的兩個方法其實是有分工的。一般來說,static getDerivedStateFromError()
是不允許發生副作用的,故是負責呈現一個備用的UI給使用者。componentDidCatch()
允許發生副作用,故負責列印錯誤日誌,傳送錯誤日誌到遠端伺服器等。如下:
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> <MyWidget /> </ErrorBoundary> 複製程式碼
<Error boundary>
使用起來就像catch {}
語句,只不過它是用於React component而已。只有class component才能成為<Error boundary>
。在實際應用中,大多數情況,你只需要定義一個<Error boundary>
,然後到處使用它。
注意,<Error boundary>
是不能捕獲自己所產生的錯誤,只能捕獲在它之下的元件樹所產生的錯誤。在<Error boundary>
巢狀使用的情況下,如果某個<Error boundary>
不能渲染一些錯誤資訊(呼叫static getDerivedStateFromError()失敗?),那麼這個錯誤就會往上冒泡到層級最近的個<Error boundary>
。這也是catch{}語句在javascript裡面的執行機制。
線上Demo
檢視ofollow,noindex">如何在React 16版本中定義和使用 error boundary 。
在哪裡“放置”Error Boundaries
在元件樹中“放置”<Error boundary>
的密度完全取決於你。你可以把你最頂級的route component包裹在<Error boundary>
中,然後讓<Error boundary>
呈現一個備用的介面給使用者,例如“Something went wrong”。服務端渲染經常就是這樣應對應用崩潰的。你也可以把多個元件分開包裹在<Error boundary>
中,以此來防止區域性UI的崩潰。