ErrorBoundary

  • react的boundary
    • 实现核心逻辑
    • 无法处理的情况
    • 包含函数详细介绍getDerivedStateFromError和componentDidCatch
      • 作用
      • 为什么分开调用
    • 代码实现(补充其他异常捕捉)
      • 函数组件与useErrorBoundary(需自定义Hook)
  • vue的boundary
    • 实现代码:
    • 全局异常捕捉:
    • 全局异步异常捕捉:
  • nuxt 的 Error boundary
    • 插件捕捉
  • 微信小程序 Error boundary
    • 实现方式
  • h5的Error boundary
  • 总结

react的boundary

react-boundary文档地址
如果没有找到 ErrorBoundary,错误会传播到全局,导致应用崩溃。

实现核心逻辑

在 React 中,当子组件抛出错误时,React 会执行以下步骤:

  1. 查找最近的 ErrorBoundary: React 会从抛出错误的组件向上查找其父组件树,寻找最近的 ErrorBoundary 组件。
  2. 调用 componentDidCatch: 如果找到 ErrorBoundary,React 会调用该组件的 componentDidCatch(error, info) 方法,传递错误信息和其他信息(如错误发生的组件树)。
  3. 更新状态: ErrorBoundary 可以根据捕获的错误更新自身的状态,通常用于显示备用 UI(如错误提示)。
  4. 渲染备用 UI: 一旦状态更新,ErrorBoundary 会重新渲染,展示备用 UI,而不是子组件的正常内容。

无法处理的情况

  • 事件处理函数(比如 onClick,onMouseEnter)
  • 异步代码(如 requestAnimationFrame,setTimeout,promise)
  • 服务端渲染
  • ErrorBoundary 组件本身的错误。

包含函数详细介绍getDerivedStateFromError和componentDidCatch

作用

getDerivedStateFromErrorcomponentDidCatch 都是 React 的错误边界方法,用于处理子组件的错误。这两个方法共同作用,确保组件能够优雅地处理和恢复错误。它们的触发时间点和方式如下:

  1. getDerivedStateFromError:
    • 触发时机: 当子组件抛出错误时,React 会首先调用这个静态方法。
    • 功能: 允许你更新状态以便在渲染错误界面之前准备新状态。
    • 返回值: 返回一个对象来更新组件状态,或者返回 null
  2. componentDidCatch:
    • 触发时机: 在 getDerivedStateFromError 之后调用,主要用于执行副作用,比如日志记录。
    • 功能: 可以处理错误信息,进行记录或其他操作。
    • 参数: 接收两个参数:错误信息和错误的组件栈。

为什么分开调用

分开调用 getDerivedStateFromErrorcomponentDidCatch 的原因主要有以下几点:

  1. 职责分离:
    • getDerivedStateFromError 专注于根据错误更新状态,以便渲染一个替代的 UI。
    • componentDidCatch 处理副作用(如日志记录),关注于错误的处理和反馈。
  2. 性能优化:
    • 分开调用允许 React 在渲染过程中优化性能,避免不必要的重新渲染。
  3. 灵活性:
    • 这种设计允许开发者在状态更新和副作用处理之间做出不同的决策,使得组件更具灵活性。
  4. 一致性:
    • getDerivedStateFromError 是一个静态方法,适用于类组件,而 componentDidCatch 是实例方法,保持了 API 的一致性。
      通过分开处理,React 能够提供更清晰的错误处理机制,提高了组件的可维护性和可读性。

代码实现(补充其他异常捕捉)

当你想补充异步等异常也同步到错误边界组件,如在一个 try-catch 语句中捕获异常并将其同步到错误边界组件,如下:

  • 事件处理函数(比如 onClick,onMouseEnter)
  • 异步代码(如 requestAnimationFrame,setTimeout,promise)
  • 服务端渲染
  • ErrorBoundary 组件本身的错误。
  1. 自定义错误边界:首先,创建一个错误边界组件,使用 componentDidCatch 捕捉错误。
class ErrorBoundary extends React.Component {constructor(props) {super(props);this.state = { hasError: false };}static getDerivedStateFromError(error) {return { hasError: true };}componentDidCatch(error, info) {// 你可以在这里记录错误信息console.error("Error caught in ErrorBoundary:", error, info);}render() {if (this.state.hasError) {return <h1>Something went wrong.</h1>;}return this.props.children;}
}
  1. 在组件中使用 try-catch:在你的组件中,使用 try-catch 捕获异常,并调用 setState 来更新错误状态。
    直接在render抛出异常throw this.state.error; // 抛出错误以让错误边界捕获
class MyComponent extends React.Component {constructor(props) {super(props);this.state = { error: null };}handleClick = () => {try {// 可能抛出错误的代码} catch (error) {this.setState({ error: true });}};render() {try {// 可能抛出异常的代码} catch (error) {this.setState({ error });}if (this.state.error) {throw this.state.error; // 抛出错误以让错误边界捕获}return <div>正常内容button onClick={this.handleClick}>Click me</button>;</div>;}
}
  1. 包裹组件:在应用中使用错误边界包裹你的组件。
<ErrorBoundary><MyComponent />
</ErrorBoundary>

函数组件与useErrorBoundary(需自定义Hook)

   function useErrorBoundary() {const [error, setError] = useState(null);const [info, setInfo] = useState(null);const handleError = (err, errorInfo) => {setError(err);setInfo(errorInfo);// 上报错误};useEffect(() => {const errorBoundary = React.useErrorBoundary(handleError);return () => errorBoundary.unsubscribe();}, []);if (error) {return <div>错误:{error.message}</div>;}return null;}

几个关键点,完善一下(还是建议官方的类方式处理):

  • 使用 useCallback 缓存错误处理函数,避免重复渲染
  • 通过动态创建类组件的方式实现错误边界功能
  • 提供了错误状态重置功能(重试按钮)
  • 展示了更友好的错误 UI,包括错误信息和组件堆栈
  • 实现了组件卸载时的资源清理
    在生产环境中使用时,还应该考虑添加以下功能:
  • 更完善的错误上报逻辑
  • 错误 UI 的样式定制
  • 错误边界的嵌套策略
  • 与 Suspense 的集成(处理异步加载错误)
import { useEffect, useState, useCallback } from 'react';function useErrorBoundary() {const [hasError, setHasError] = useState(false);const [error, setError] = useState(null);const [errorInfo, setErrorInfo] = useState(null);// 错误处理函数const handleError = useCallback((err, info) => {setHasError(true);setError(err);setErrorInfo(info);// 上报错误到监控系统console.error('Error Boundary Captured:', err, info);reportErrorToService(err, info); // 假设这是一个错误上报函数}, []);// 用于捕获后代组件错误的 effectuseEffect(() => {// 创建一个错误边界实例class ErrorBoundary extends React.Component {componentDidCatch(error, errorInfo) {handleError(error, errorInfo);}render() {return this.props.children;}}// 为当前组件创建一个错误边界包装器const ErrorBoundaryWrapper = ({ children }) => (<ErrorBoundary>{children}</ErrorBoundary>);// 将错误边界包装器挂载到当前组件const wrapperElement = document.createElement('div');document.body.appendChild(wrapperElement);// 渲染错误边界组件const root = ReactDOM.createRoot(wrapperElement);root.render(<ErrorBoundaryWrapper>{children}</ErrorBoundaryWrapper>);// 清理函数return () => {root.unmount();document.body.removeChild(wrapperElement);};}, [handleError]);// 重置错误状态const resetErrorBoundary = useCallback(() => {setHasError(false);setError(null);setErrorInfo(null);}, []);// 错误发生时返回错误 UIif (hasError) {return (<div className="error-boundary"><div className="error-message"><h2>发生错误</h2><p>{error?.message || '未知错误'}</p>{errorInfo && (<div className="error-details"><h3>错误详情</h3><pre>{errorInfo.componentStack}</pre></div>)}</div><button onClick={resetErrorBoundary}>重试</button></div>);}// 没有错误时返回 nullreturn null;
}// 示例使用方法
function MyComponent() {const errorBoundary = useErrorBoundary();return (<div>{errorBoundary}<RiskyComponent /> {/* 可能抛出错误的组件 */}</div>);
}

vue的boundary

在 Vue 中,实现这个用errorCaptured捕捉
其中,errorCaptured 钩子可以捕捉到以下类型的错误:

  1. 子组件的生命周期钩子中的错误:如 createdmounted 等。
  2. 渲染函数中的错误:在模板或渲染函数中发生的错误。
  3. 事件处理器中的错误:在事件处理函数中抛出的错误。
    但是,errorCaptured 无法捕捉到以下类型的错误:
  4. 全局未处理的 Promise 拒绝:这些错误需要使用全局的 window.onunhandledrejection 来捕获。
  5. 异步操作中的错误:如 setTimeoutsetInterval 中的错误,除非在其中手动捕获并处理。
  6. Vue 实例的错误:如在根实例中发生的错误,需在全局范围内捕获。
    总之,errorCaptured 主要用于捕捉组件内部的错误,而不适用于全局或异步错误。

实现代码:

<!-- AdvancedErrorBoundary.vue -->
<template><div><slot v-if="!errorState" name="default"></slot><slot v-else name="fallback" :error="errorState"><div class="error-view"><h3>⚠️ 组件异常</h3><p>{{ errorState.message }}</p><button @click="reset">重新加载</button></div></slot></div>
</template><script>
export default {data: () => ({errorState: null}),errorCaptured(err, vm, info) {this.errorState = {error: err,component: vm,info,timestamp: Date.now()};this.reportError(err); // 错误上报return false;},methods: {reset() {this.errorState = null;},reportError(err) {// 发送错误到监控系统}}
};
</script>

实际应用(异步捕捉手动触发错误边界):


export default {components: { ErrorBoundary },methods: {async fetchData() { //handleClick 点击事件同理try {// 异步操作await apiCall();} catch (e) {// 1. 手动触发错误边界this.$emit('error', e); // 2. 或调用父组件方法if (this.parentErrorHandler) {this.parentErrorHandler(e);}}},
};
</script>

全局异常捕捉:

// vue2
Vue.config.errorHandler = (err, vm, info) => {// 1. 处理全局错误console.error('Global error:', err, info);// 2. 显示全局错误提示showGlobalErrorOverlay();
};
// vue3
app.config.errorHandler = (err, vm, info) => {// 错误处理逻辑
};

全局异步异常捕捉:

通过 window.addEventListener('unhandledrejection') 捕获。

nuxt 的 Error boundary

nuxt的组件方式实现,是基于vue的errorCaptured,全局如下:

插件捕捉

// 创建插件 plugins/error-handler.js
export default function ({ error }) {// 可在此处添加错误上报逻辑console.error('Nuxt 错误捕获:', error);
}
// 并在 nuxt.config.js 中注册
export default {plugins: ['~/plugins/error-handler'],
};

微信小程序 Error boundary

实现方式

// components/ErrorBoundary/index.js
Component({options: {multipleSlots: true, // 启用多slot支持},properties: {fallback: {type: String,value: '页面加载失败,请稍后再试',},showError: {type: Boolean,value: false,},},data: {hasError: false,errorInfo: '',},methods: {// 重置错误状态resetErrorBoundary() {this.setData({hasError: false,errorInfo: '',});// 触发自定义事件通知父组件this.triggerEvent('reset');},},// 组件生命周期函数,在组件实例进入页面节点树时执行attached() {this.setData({hasError: this.properties.showError,});},// 错误捕获处理函数pageLifetimes: {show() {// 页面显示时重置错误状态(可选)if (this.data.hasError) {this.resetErrorBoundary();}},},// 捕获当前组件错误lifetimes: {error(err) {console.error('ErrorBoundary捕获到错误:', err);this.setData({hasError: true,errorInfo: err.toString(),});// 触发自定义事件通知父组件this.triggerEvent('error', { error: err });},},
});    

使用方式

// wxml
<!-- 在页面中使用ErrorBoundary -->
<ErrorBoundary fallback="组件加载失败" bind:error="handleError" bind:reset="handleReset"><!-- 可能出错的组件 --><RiskyComponent />
</ErrorBoundary>
// js
// 页面JS
Page({methods: {handleError(e) {console.log('页面收到错误信息:', e.detail.error);// 可以在这里添加错误上报逻辑},handleReset() {console.log('用户点击了重试按钮');// 可以在这里添加重新加载数据的逻辑},},
});

h5的Error boundary

在纯HTML/JavaScript环境中实现类似React的Error Boundaries功能需要创建一个自定义的错误边界组件,能够捕获子元素的渲染错误并提供降级UI。

<script>// 错误边界实现const errorBoundaries = {};function createErrorBoundary(containerId) {const container = document.getElementById(containerId);let hasError = false;let error = null;let errorInfo = null;function render() {if (!hasError) {container.innerHTML = `<div class="error-boundary-content"><div class="safe-component"><div class="component-title">安全组件</div><div class="component-content">这个组件运行正常</div></div><div class="unstable-component"><div class="component-title">不稳定组件</div><div class="component-content">点击按钮触发错误</div></div></div>`;} else {container.innerHTML = `<div class="error-ui"><div class="error-header"><span class="error-icon">⚠️</span><div class="error-title">组件渲染错误</div></div><div class="error-message">${error.message}</div><div class="actions"><button class="retry-btn" onclick="resetBoundary('${containerId}')">重试</button><button class="report-btn" onclick="reportError()">报告问题</button></div></div>`;}}function captureError(err, info) {hasError = true;error = err;errorInfo = info;render();console.error('ErrorBoundary caught:', err, info);}function reset() {hasError = false;error = null;errorInfo = null;render();}// 初始渲染render();return {captureError,reset};}// 创建错误边界实例errorBoundaries['boundary1'] = createErrorBoundary('boundary1');errorBoundaries['boundary2'] = createErrorBoundary('boundary2');// 触发错误函数function triggerError(boundaryId) {try {// 模拟一个可能出错的函数const invalidObj = null;// 故意访问null对象的属性来抛出错误invalidObj.someProperty = 'test';} catch (error) {// 捕获错误并传递给错误边界errorBoundaries[`boundary${boundaryId}`].captureError(new Error('组件渲染时发生错误: ' + error.message),{ componentStack: '在UnstableComponent中' });}}// 重置错误边界function resetBoundary(boundaryId) {errorBoundaries[boundaryId].reset();}// 报告错误function reportError() {alert('错误已报告给开发团队,感谢您的反馈!');}// 初始化时随机触发一个错误setTimeout(() => {if (Math.random() > 0.5) {triggerError(2);}}, 1500);
</script>

使用方式

// 创建错误边界
const boundary = createErrorBoundary('containerId');// 在可能出错的地方捕获错误
try {// 可能出错的代码
} catch (error) {boundary.captureError(error, { componentStack: '...' });
}// 重置错误边界
boundary.reset();

总结

Vue 与 React 的差异:

  1. Vue 的错误捕获是单向的(父 → 子),而 React 是双向的(子 → 父)。
    Vue 的 errorCaptured 钩子仅捕获渲染期间的错误,不捕获异步错误(如 Promise 错误)。
  2. 异步错误处理:
    全局异步错误需通过 window.addEventListener(‘unhandledrejection’) 捕获。
    在 Nuxt 中,异步错误可通过 try…catch 或全局错误页面处理。
  3. 生产环境错误上报:
    建议集成 Sentry 等错误监控工具,在错误捕获时自动上报。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/87505.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/87505.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/87505.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Day113 切换Node.js版本、多数据源配置

切换Node.js版本 1.nvm简介nvm(Node Version Manager)&#xff0c;在Windows上管理Node.js版本&#xff0c;可以在同一台电脑上轻松管理和切换多个Node.js版本 nvm下载地址&#xff1a;https://github.com/coreybutler/nvm-windows/2.配置nvm安装之后检查nvm是否已经安装好了&a…

应急响应靶机-linux2-知攻善防实验室

题目&#xff1a; 1.提交攻击者IP2.提交攻击者修改的管理员密码(明文)3.提交第一次Webshell的连接URL(http://xxx.xxx.xxx.xx/abcdefg?abcdefg只需要提交abcdefg?abcdefg)4.提交Webshell连接密码5.提交数据包的flag16.提交攻击者使用的后续上传的木马文件名称7.提交攻击者隐藏…

新手前端使用Git(常用命令和规范)

发一篇文章来说一下前端在开发项目的时候常用的一些git命令 注&#xff1a;这篇文章只说最常用的&#xff0c;最下面有全面的 一&#xff1a;从git仓库拉取项目到本地 1&#xff1a;新建文件夹存放项目代码 2&#xff1a;在git上复制一下项目路径&#xff08;看那个顺眼复制…

【面试题】常用Git命令

【面试题】常用Git命令1. 常用Git命令1. 常用Git命令 1.git clone git clone https://gitee.com/Blue_Pepsi_Cola/straw.git 2.使用-v选项&#xff0c;可以参看远程主机的网址 git remote -v origin https://ccc.ddd.com/1-java/a-admin-api.git (fetch) origin https://ccc.…

Webpack构建工具

构建工具系列 Gulp构建工具Grunt构建工具Webpack构建工具Vite构建工具 Webpack构建工具 构建工具系列前言一、安装打包配置webpack安装样式加载器devtoolwebpack devtool 配置详解常见 devtool 值及适用场景选择建议性能影响注意事项 module处理流程module.rulesmodule.usemod…

重学前端002 --响应式网页设计 CSS

文章目录 css 样式特殊说明 根据在这里 Freecodecamp 实践&#xff0c;调整顺序后做的总结。 css 样式 body {background-color: red; # 跟background-image 不同时使用background-image: url(https://cdn.freecodecamp.org/curriculum/css-cafe/beans.jpg);font-family: san…

RabbitMQ简单消息监听和确认

如何监听RabbitMQ队列 简单代码实现RabbitMQ消息监听 需要的依赖 <!--rabbitmq--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId><version>x.x.x</version>&l…

Docker学习笔记:Docker网络

本文是自己的学习笔记 1、Linux中的namespace1.1、创建namespace1.2、两个namespace互相通信2、Docker中的namespace2.1 容器中的默认Bridge3、容器的三种网络模式1、Linux中的namespace Docker中使用了虚拟网络技术&#xff0c;让各个容器的网络隔离。好像每个容器从网卡到端…

用自定义注解解决excel动态表头导出的问题

导入的excel有固定表头动态表头如何解决 自定义注解&#xff1a; import java.lang.annotation.*;/*** 自定义注解&#xff0c;用于动态生成excel表头*/ Target(ElementType.FIELD) Retention(RetentionPolicy.RUNTIME) public interface FieldLabel {// 字段中文String label(…

Android-EDLA 解决 GtsMediaRouterTestCases 存在 fail

问题描述&#xff1a;[原因]R10套件新增模块&#xff0c;getRemoteDevice获取远程蓝牙设备时&#xff0c;蓝牙MAC为空 [对策]实际蓝牙MAC非空;测试时绕过处理 1.release/ebsw_skg/skg/frameworks/base/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManage…

双涡轮增压器结构设计cad【5张】+设计说明书

摘要 随着汽车制造商和消费者对动力性能的要求不断增加&#xff0c;发动机需要在更宽的转速范围内提供更大的功率和扭矩。双涡轮增压器可以帮助实现这一目标&#xff0c;通过在不同转速下调整涡轮的工作状态来提供更平顺的动力输出。单一涡轮增压器可能存在涡轮滞后和增压延迟…

大数据轻量化流批一体架构探索实践(一)

最近学习了解到一种轻量化&#xff0c;维护门槛较低的流批一体化的架构方式&#xff0c;虽然目前还是不太成熟&#xff0c;自己也在探索学习中。 dolphinschedulerdinkystarrocksflinkzookeper 后面我会逐步发一下这个整体架构的特点&#xff0c;以及各个组件作用&#xff0c;和…

【2025/07/04】GitHub 今日热门项目

GitHub 今日热门项目 &#x1f680; 每日精选优质开源项目 | 发现优质开源项目&#xff0c;跟上技术发展趋势 &#x1f4cb; 报告概览 &#x1f4ca; 统计项&#x1f4c8; 数值&#x1f4dd; 说明&#x1f4c5; 报告日期2025-07-04 (周五)GitHub Trending 每日快照&#x1f55…

HarmonyOS学习记录3

HarmonyOS学习记录3 本文为个人学习记录&#xff0c;仅供参考&#xff0c;如有错误请指出。本文主要记录ArkTS基础语法&#xff0c;仅记录了部分我觉得与其他语言不太类似的地方&#xff0c;具体规范请参考官方文档。 参考官方文档&#xff1a;https://developer.huawei.com/co…

HKS201-M24 大师版 8K60Hz USB 3.0 适用于 2 台 PC 1台显示器 无缝切换 KVM 切换器

HKS201-M24 8K60Hz HDMI 2.1 2x1 KVM 切换器&#xff0c;适用于 2 台 PC&#xff0c;带 EDID 仿真、千兆 LAN、双充电和 USB 3.2 Gen 1 HKS201-M24 产品概述 TESmart 重新定义智能工作空间&#xff0c;无缝双PC控制。 真正的 8K60Hz 亮度&#xff0c;具有 EDID 稳定性和超快速…

stm32f103vct6的DAC口的输出电压达不到3.3V

问题&#xff1a;调试时发现自己设置的DAC在最大时达不到3.3V&#xff0c;总结了原因&#xff0c;记录下。 原因&#xff1a;使用时&#xff0c;注意有没有其他负载&#xff0c;有的话最好给负载独立供电&#xff0c;不要只用STM32f103的板凑活着供电&#xff0c;我的就是这个…

java8 Collectors.mapping 使用 例子 学习

java8 Collectors.mapping 使用 例子 学习 Map<String, List<String>> colorApple appleList.stream().collect(Collectors.groupingBy(Apple::getColor, Collectors.mapping(Apple::getVariety, toList()))); colorApple.forEach((k, v) -> {System.out.prin…

动态规划-P1216 [IOI 1994] 数字三角形 Number Triangles

P1216 [IOI 1994] 数字三角形 Number Triangles 题目来源-洛谷题库 思路 如果用贪心只是找当前的到达该点的路径最大值&#xff0c;可能结果无法做到最优最值问题试着看能否将大问题分解成若干个小问题 走到a[i] [j ]这个点的最值来源于上一步a[i-1 ] [j]和a[i-1] [j-1]的最…

25年Java后端社招技术场景题!

一、电商领域高频场景题1. 百万级QPS秒杀系统设计场景需求&#xff1a;设计一个支持百万级QPS的秒杀系统&#xff0c;要求解决超卖问题&#xff0c;保证系统高可用。技术方案&#xff1a;分层削峰&#xff1a;前端页面静态化按钮防重复点击Redis集群&#xff1a;采用Lua脚本实现…

牛客:HJ16 购物单【01背包】【华为机考】

学习要点 深入理解回溯深入理解01背包问题 题目链接 购物单_牛客题霸_牛客网 题目描述 解法1&#xff1a;回溯 其实此题非常符合取子集的逻辑&#xff0c;但是时间复杂度太高。通过11/14。想写出来这个回溯过程&#xff0c;不容易。 #include <iostream> #include &l…