詳解React 16 中的異常處理
詳解React 16 中的異常處理
異常處理
在 React 15.x 及之前的版本中,組件內(nèi)的異常有可能會(huì)影響到 React 的內(nèi)部狀態(tài),進(jìn)而導(dǎo)致下一輪渲染時(shí)出現(xiàn)未知錯(cuò)誤。這些組件內(nèi)的異常往往也是由應(yīng)用代碼本身拋出,在之前版本的 React 更多的是交托給了開(kāi)發(fā)者處理,而沒(méi)有提供較好地組件內(nèi)優(yōu)雅處理這些異常的方式。在 React 16.x 版本中,引入了所謂 Error Boundary 的概念,從而保證了發(fā)生在 UI 層的錯(cuò)誤不會(huì)連鎖導(dǎo)致整個(gè)應(yīng)用程序崩潰;未被任何異常邊界捕獲的異??赡軙?huì)導(dǎo)致整個(gè) React 組件樹(shù)被卸載。所謂的異常邊界即指某個(gè)能夠捕獲它的子元素(包括嵌套子元素等)拋出的異常,并且根據(jù)用戶(hù)配置進(jìn)行優(yōu)雅降級(jí)地顯示而不是導(dǎo)致整個(gè)組件樹(shù)崩潰。異常邊界能夠捕獲渲染函數(shù)、生命周期回調(diào)以及整個(gè)組件樹(shù)的構(gòu)造函數(shù)中拋出的異常。
我們可以通過(guò)為某個(gè)組件添加新的 componentDidCatch(error, info) 生命周期回調(diào)來(lái)使其變?yōu)楫惓_吔纾?/p>
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error, info) { // Display fallback UI this.setState({ hasError: true }); // 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>
componentDidCatch() 方法就好像針對(duì)組件的 catch {} 代碼塊;不過(guò) JavaScript 中的 try/catch 模式更多的是面向命令式代碼,而 React 組件本身是聲明式模式,因此更適合采用指定渲染對(duì)象的模式。需要注意的是僅有類(lèi)組件可以成為異常邊界,在真實(shí)的應(yīng)與開(kāi)發(fā)中我們往往會(huì)聲明單個(gè)異常邊界然后在所有可能拋出異常的組件中使用它。另外值得一提的是異常邊界并不能捕獲其本身的異常,如果異常邊界組件本身拋出了異常,那么會(huì)冒泡傳遞到上一層最近的異常邊界中。
在真實(shí)地應(yīng)用開(kāi)發(fā)中有的開(kāi)發(fā)者也會(huì)將崩壞的界面直接展示給開(kāi)發(fā)者,不過(guò)譬如在某個(gè)聊天界面中,如果在出現(xiàn)異常的情況下仍然直接將界面展示給用戶(hù),就有可能導(dǎo)致用戶(hù)將信息發(fā)送給錯(cuò)誤的接受者;或者在某些支付應(yīng)用中導(dǎo)致用戶(hù)金額顯示錯(cuò)誤。因此如果我們將應(yīng)用升級(jí)到 React 16.x,我們需要將原本應(yīng)用中沒(méi)有被處理地異常統(tǒng)一包裹進(jìn)異常邊界中。譬如某個(gè)應(yīng)用中可能會(huì)分為側(cè)邊欄、信息面板、會(huì)話界面、信息輸入等幾個(gè)不同的模塊,我們可以將這些模塊包裹進(jìn)不同的錯(cuò)誤邊界中;這樣如果某個(gè)組件發(fā)生崩潰,會(huì)被其直屬的異常邊界捕獲,從而保證剩余的部分依然處于可用狀態(tài)。同樣的我們也可以在異常邊界中添加錯(cuò)誤反饋等服務(wù)接口以及時(shí)反饋生產(chǎn)環(huán)境下的異常并且修復(fù)他們。完整的應(yīng)用代碼如下所示:
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; } } class BuggyCounter extends React.Component { constructor(props) { super(props); this.state = { counter: 0 }; this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(({counter}) => ({ counter: counter + 1 })); } render() { if (this.state.counter === 5) { // Simulate a JS error throw new Error('I crashed!'); } return <h1 onClick={this.handleClick}>{this.state.counter}</h1>; } } function App() { return ( <div> <p> <b> This is an example of error boundaries in React 16. <br /><br /> Click on the numbers to increase the counters. <br /> The counter is programmed to throw when it reaches 5. This simulates a JavaScript error in a component. </b> </p> <hr /> <ErrorBoundary> <p>These two counters are inside the same error boundary. If one crashes, the error boundary will replace both of them.</p> <BuggyCounter /> <BuggyCounter /> </ErrorBoundary> <hr /> <p>These two counters are each inside of their own error boundary. So if one crashes, the other is not affected.</p> <ErrorBoundary><BuggyCounter /></ErrorBoundary> <ErrorBoundary><BuggyCounter /></ErrorBoundary> </div> ); } ReactDOM.render( <App />, document.getElementById('root') );
以上就是詳解React 16 中的異常處理的資料整理,如有疑問(wèn)請(qǐng)留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
React中super()和super(props)的區(qū)別小結(jié)
本文主要介紹了React中super()和super(props)的區(qū)別小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03淺談React的React.FC與React.Component的使用
本文主要介紹了React的React.FC與React.Component的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09React+CSS 實(shí)現(xiàn)繪制橫向柱狀圖
這篇文章主要介紹了React+CSS 實(shí)現(xiàn)繪制橫向柱狀圖,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09使用React Native創(chuàng)建以太坊錢(qián)包實(shí)現(xiàn)轉(zhuǎn)賬等功能
這篇文章主要介紹了使用React Native創(chuàng)建以太坊錢(qián)包,實(shí)現(xiàn)轉(zhuǎn)賬等功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07ReactJS實(shí)現(xiàn)表單的單選多選和反選的示例
本篇文章主要介紹了ReactJS實(shí)現(xiàn)表單的單選多選和反選的示例,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-10-10