在 React 中,如果不做任何控制,当组件出现异常时,React 渲染就会停止,页面出现白屏,这种体验很不好。例如当用户输入某些非法数据,而前端都没有进行校验,页面出现白屏。这种情况下,最好的方式是只针对出错的组件进行处理,将出错的组件进行替换,替换成错误提示组件,并显示错误信息,可以指导用户的下一步操作。React 通过 ErrorBoundary 组件进行错误处理,当组件出现错误时,组件停止当前渲染并通过 Fiber 向上查找,如果找到 ErrorBoundary,就显示 Fallback 组件,否则出现白屏。
看一个简单的例子,主要看 Error 组件,当抛出异常时,会显示白屏。
### App 组件 export default function App() { const AList = lazy(()=>import('./List.js')) const r = useRef(null) const [show, setShow] = useState(false); return ( <>> ); } ### Error 组件 import React from 'react'; export function ErrorComponent(){ // throw new Error('出错了!!'); return {"text-align":"center", "font-size":"50px","color":"red"}}>错误; }
异常被注释掉时,组件正常显示。
打开注释,页面崩溃。
getDerivedStateFromError
在 React 中,如果想捕获子组件的异常需要定义 getDerivedStateFromError,当子组件出现异常时 React 会调用这个方法。ErrorBoundary 需要是一个类组件,在组件中定义 getDerivedStateFromError 方法。以下代码实现了 ErrorBoundary 组件,重点看 getDerivedStateFromError 方法。
import React, { Component } from 'react'; class ErrorBoundary extends Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // Update state so the next render shows the fallback UI. return { hasError: true }; } componentDidCatch(error, errorInfo) { // You can also log the error to an error reporting service console.log('Logging error:', error, errorInfo); } render() { if (this.state.hasError) { return组件出现异常
; } return this.props.children; } } export default ErrorBoundary;
将 ErrorComponent 设置为 Boundary 的子组件,组件被替换。
React 如何实现
跟踪一下 React 代码,看 React 如何实现 getDerivedStateFromError,在组件发生异常时通过 try/catch 捕获并进入 handleError 方法
进入 handleError 并调用 throwException 方法
在 throwException 中判断是否存在 getDerivedStateFromError 方法,如果存在继续处理,进入createClassErrorUpdate
创建 update 并返回,update.payload 方法会调用 getDerivedStateFromError
将 update 加入 WIP 中的 updateQueue
从throwException 返回,进入 completeUnitOfWork,并返回 returnFiber (ErrorBoundary)。
最后最近进入finishClassComponent 渲染组件
总结
React 框架中通过 getDerivedStateFromError 方法进行异常处理,项目开发可以自定义一个类组件并实现该方法进行组件异常处理。
还没有评论,来说两句吧...