这是React16的内容,并不是最新的技能,可是用很少被接头,直到通过文档发明其实也是很有用的一部门内容,照旧总结一下~
React中的未捕捉的 JS 错误会导致整个应用的瓦解,和整个组件树的卸载。从 React16 开始就是这样。可是同时React也引入了一个新的观念——错误界线。
界说,是什么错误界线仍然是一种组件,可以捕捉(打印可能其他方法)处理惩罚该组件的子组件树任何位置的 JavaScript 错误,并按照需要渲染出备用UI.
事情方法雷同于try-catch,可是错误界线只用于 React 组件。
只有class组件可以或许成为错误界线组件。错误界线仅可以捕捉子组件的错误,无法捕捉自身的错误。
错误界线会在渲染期间,生命周期和整个组件树的结构函数中捕捉错误。假如没有错误界线处理惩罚,渲染的照旧瓦解的子组件树,这显然不是我们想要的。
通过一个例子来慢慢演示要怎么用错误界线:
export default class ErrorTest extends Component { constructor(props) { super(props); } render() { return ( <div> <BugCounter></BugCounter> <span>my name is dan</span> </div> ); } } // Bug 报错组件 class BugCounter extends Component { constructor(props) { super(props); this.state = { counter: 0, }; } click = () => { this.setState(({ counter }) => ({ counter: counter + 1 })); }; render() { if (this.state.counter === 5) { throw new Error("crashed!"); } return ( <div> <h3 onClick={this.click}>{this.state.counter}</h3> </div> ); } }
上面代码的渲染功效(忽略样式):
点击数字0,会慢慢递增。可是数字便是5的时候,组件会抛出一个Error:
该Error会引起整个Demo的瓦解,连外部的<span>my name is dan</span>也显示不出来了,这时还没有添加错误界线。
出产模式下,会直接白屏,并在节制台报错:
getDerivedStateFromError & componentDidCatch
需要一个错误界线来处理惩罚这种瓦解。如何界说一个错误界线?
界说一个组件,并实现static getDerivedStateFromError() 可能componentDidCatch() 生命周期要领(可以都实现可能选择其一)。这个组件就会酿成一个错误界线。
关于这两个生命周期函数,可以通过链接查察,总结如下:
componentDidCatch(error, info)
error是抛出的错误工具,而info则包括了组件激发错误的栈信息。函数在提交阶段被挪用。是可以执行副浸染的。
static getDerivedStateFromError(error)
在子组件抛堕落误后挪用,会将抛出的错误作为参数。需要返回一个值,以更新state。该函数在渲染阶段挪用,不答允呈现副浸染。假如在捕捉错误后需要执行副浸染操纵,应该在componentDidCatch中举办。
建造错误界线组件可以利用组合的方法,在要利用的组件上面添加一个错误界线组件包裹一层。该组件需要这些结果:
捕捉子组件错误,组件内部记录堕落状态
在堕落状态下显示备用UI,在正常状态下显示子组件
那么就可以像这样:
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; } }
捕捉到错误之后的副浸染是自界说的,上传处事器,可能用state记录再显示在页面上:
componentDidCatch(error, errorInfo) { // Catch errors in any components below and re-render with error message this.setState({ error: error, errorInfo: errorInfo }) }
捕捉处理惩罚加上所有代码,将有问题的组件用错误界线的组件包裹起来,看当作果:
import { Component } from "react"; export default class ErrorTest extends Component { render() { return ( <div> <ErrorBoundary> <BugCounter></BugCounter> </ErrorBoundary> <span>my name is dan</span> </div> ); } } // Bug 报错组件 class BugCounter extends Component { constructor(props) { super(props); this.state = { counter: 0, }; } click = () => { this.setState(({ counter }) => ({ counter: counter + 1 })); }; render() { if (this.state.counter === 5) { throw new Error("crashed!"); } return ( <div> <h3 onClick={this.click}>{this.state.counter}</h3> </div> ); } } // 错误界线处理惩罚组件 class ErrorBoundary extends Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // 更新 state 使下一次渲染可以或许显示降级后的 UI return { hasError: true }; } render() { if (this.state.hasError) { // 你可以自界说降级后的 UI 并渲染 return <h1>Something went wrong.</h1>; } return this.props.children; } }
抛出异常在开拓模式下依然是报错的,可是在利用yarn build之后,再通过http-server挂起来之后,会见出产的页面: