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

















 
 
 






 
 
 
 