当前位置: 首页 > news >正文

React 错误边界组件 react-error-boundary 源码解析

文章目录

  • 捕获错误 hook
  • 创建错误边界组件 Provider
  • 定义错误边界组件
    • 定义边界组件状态
    • 捕捉错误
    • 渲染备份组件
    • 重置组件
    • 通过 useHook 控制边界组件

捕获错误 hook

  • getDerivedStateFromError
    • 返回值会作为组件的 state 用于展示错误时的内容
  • componentDidCatch

创建错误边界组件 Provider

  • 错误边界组件其实是一个通过 Context.Provider 包裹的组件,这样使得组件内部可以获取到捕捉的相关操作
import { createContext } from "react";export type ErrorBoundaryContextType = {didCatch: boolean;error: any;resetErrorBoundary: (...args: any[]) => void;
};// 错误边界组件其实是一个通过 Context.Provider 包裹的组件
export const ErrorBoundaryContext =createContext<ErrorBoundaryContextType | null>(null);

定义错误边界组件

定义边界组件状态

type ErrorBoundaryState =| {didCatch: true;error: any;}| {didCatch: false;error: null;};const initialState: ErrorBoundaryState = {didCatch: false, // 错误是否捕捉error: null, // 捕捉到的错误信息
};

捕捉错误

  • getDerivedStateFromError 捕捉到错误后,设置组件状态展示备份组件
  • componentDidCatch 用于触发错误回调
export class ErrorBoundary extends Component<ErrorBoundaryProps,ErrorBoundaryState
> {constructor(props: ErrorBoundaryProps) {super(props);this.resetErrorBoundary = this.resetErrorBoundary.bind(this);this.state = initialState;}static getDerivedStateFromError(error: Error) {return { didCatch: true, error };}componentDidCatch(error: Error, info: ErrorInfo) {this.props.onError?.(error, info);}}

渲染备份组件

  • 通过指定的参数名区分是无状态组件还是有状态组件
    • 无状态组件通过直接调用函数传递 props
    • 有状态组件通过 createElement 传递 props
  • 通过 createElement 处理传递的组件更加优雅
    • createElement(元素类型,参数,子元素)详情,其中第一个参数可以直接传递 Context.Provider
export class ErrorBoundary extends Component<ErrorBoundaryProps,ErrorBoundaryState
> {// ...render() {const { children, fallbackRender, FallbackComponent, fallback } =this.props;const { didCatch, error } = this.state;let childToRender = children;// 如果捕捉到了错误if (didCatch) {const props: FallbackProps = {error,resetErrorBoundary: this.resetErrorBoundary,};// 通过指定的参数名区分是无状态组件还是有状态组件if (typeof fallbackRender === "function") {childToRender = fallbackRender(props);} else if (FallbackComponent) {childToRender = createElement(FallbackComponent, props);} else if (fallback === null || isValidElement(fallback)) {childToRender = fallback;} else {if (isDevelopment) {console.error("react-error-boundary requires either a fallback, fallbackRender, or FallbackComponent prop");}throw error;}}// Context.Provider 可以直接作为 createElement 的第一个参数return createElement(ErrorBoundaryContext.Provider,{value: { // Context.Provider 提供可供消费的内容didCatch,error,resetErrorBoundary: this.resetErrorBoundary,},},childToRender);}// ...
}

重置组件

  • 将错误信息重置使得能渲染原组件
const initialState: ErrorBoundaryState = {didCatch: false, // 错误是否捕捉error: null, // 捕捉到的错误信息
};export class ErrorBoundary extends Component<ErrorBoundaryProps,ErrorBoundaryState
> {// ...resetErrorBoundary(...args: any[]) {const { error } = this.state;if (error !== null) {this.props.onReset?.({ // 触发对应回调args,reason: "imperative-api",});this.setState(initialState);}}// ...// 根据 resetKeys 重置,但并未对外暴露该 APIcomponentDidUpdate(prevProps: ErrorBoundaryProps,prevState: ErrorBoundaryState) {const { didCatch } = this.state;const { resetKeys } = this.props;// There's an edge case where if the thing that triggered the error happens to *also* be in the resetKeys array,// we'd end up resetting the error boundary immediately.// This would likely trigger a second error to be thrown.// So we make sure that we don't check the resetKeys on the first call of cDU after the error is set.if (didCatch &&prevState.error !== null &&hasArrayChanged(prevProps.resetKeys, resetKeys)) {this.props.onReset?.({next: resetKeys,prev: prevProps.resetKeys,reason: "keys",});this.setState(initialState);}}
}function hasArrayChanged(a: any[] = [], b: any[] = []) {return (a.length !== b.length || a.some((item, index) => !Object.is(item, b[index])));
}

通过 useHook 控制边界组件

  • 通过 context 获取最近的边界组件内容
  • 通过手动抛出错误重新触发边界组件
import { useContext, useMemo, useState } from "react";
import { assertErrorBoundaryContext } from "./assertErrorBoundaryContext";
import { ErrorBoundaryContext } from "./ErrorBoundaryContext";type UseErrorBoundaryState<TError> =| { error: TError; hasError: true }| { error: null; hasError: false };export type UseErrorBoundaryApi<TError> = {resetBoundary: () => void;showBoundary: (error: TError) => void;
};export function useErrorBoundary<TError = any>(): UseErrorBoundaryApi<TError> {// 获取最近的边界组件 Provider 的内容const context = useContext(ErrorBoundaryContext);// 断言 Context 是否为空assertErrorBoundaryContext(context);const [state, setState] = useState<UseErrorBoundaryState<TError>>({error: null,hasError: false,});const memoized = useMemo(() => ({resetBoundary: () => {// 提供 Provider 对应的重置边界组件方法,渲染原组件context.resetErrorBoundary();setState({ error: null, hasError: false });},// 手动抛出错误,触发边界组件showBoundary: (error: TError) =>setState({error,hasError: true,}),}),[context.resetErrorBoundary]);// 当调用 showBoundary 后,该 hook 会手动抛出错误,让边界组件来捕捉if (state.hasError) {throw state.error;}return memoized;
}

相关文章:

React 错误边界组件 react-error-boundary 源码解析

文章目录 捕获错误 hook创建错误边界组件 Provider定义错误边界组件定义边界组件状态捕捉错误渲染备份组件重置组件通过 useHook 控制边界组件 捕获错误 hook getDerivedStateFromError 返回值会作为组件的 state 用于展示错误时的内容 componentDidCatch 创建错误边界组件 P…...

分享66个相册特效,总有一款适合您

分享66个相册特效&#xff0c;总有一款适合您 66个相册特效下载链接&#xff1a;https://pan.baidu.com/s/1jqctaho4sL_iGSNExhWB6A?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不…...

chagpt的原理详解

GPT&#xff08;Generative Pre-trained Transformer&#xff09;是一种基于Transformer架构的生成式预训练模型。GPT-3是其中的第三代&#xff0c;由OpenAI开发。下面是GPT的基本原理&#xff1a; Transformer架构&#xff1a; GPT基于Transformer架构&#xff0c;该架构由Att…...

dockerfile 详细讲解

当编写 Dockerfile 时&#xff0c;你需要考虑你的应用程序所需的环境和依赖项&#xff0c;并将其描述为一系列指令。下面是一个简单的示例&#xff0c;演示如何编写一个用于部署基于 Node.js 的网站的 Dockerfile&#xff1a; Dockerfile # 使用官方 Node.js 镜像作为基础镜像…...

跟着pink老师前端入门教程-day23

苏宁网首页案例制作 设置视口标签以及引入初始化样式 <meta name"viewport" content"widthdevice-width, user-scalableno, initial-scale1.0, maximum-scale1.0, minimum-scale1.0"> <link rel"stylesheet" href"css/normaliz…...

JRT监听程序

本次设计避免以往设计缺陷&#xff0c;老的主要为了保持兼容性&#xff0c;在用的设计就不好调了。 首先&#xff0c;接口抽象时候就不在给参数放仪器ID和处理类了&#xff0c;直接放仪器配置实体&#xff0c;接口实现想用什么属性就用什么属性&#xff0c;避免老方式要扩参数时…...

MCU+SFU视频会议一体化,视频监控,指挥调度(AR远程协助)媒体中心解决方案。

视频互动应用已经是政务和协同办公必备系统&#xff0c;早期的分模块&#xff0c;分散的视频应该不能满足业务需要&#xff0c;需要把视频监控&#xff0c;会议&#xff0c;录存一体把视频资源整合起来&#xff0c;根据客户需求&#xff0c;需要能够多方视频互动&#xff0c;直…...

1184. 欧拉回路(欧拉回路,模板题)

活动 - AcWing 给定一张图&#xff0c;请你找出欧拉回路&#xff0c;即在图中找一个环使得每条边都在环上出现恰好一次。 输入格式 第一行包含一个整数 t&#xff0c;t∈{1,2}&#xff0c;如果 t1&#xff0c;表示所给图为无向图&#xff0c;如果 t2&#xff0c;表示所给图为…...

学习 Redis 基础数据结构,不讲虚的。

学习 Redis 基础数据结构&#xff0c;不讲虚的。 一个群友给我发消息&#xff0c;“该学的都学了&#xff0c;怎么就找不到心意的工作&#xff0c;太难了”。 很多在近期找过工作的同学一定都知道了&#xff0c;背诵八股文已经不是找工作的绝对王牌。企业最终要的是可以创造价…...

Android 11 webview webrtc无法使用问题

问题&#xff1a;Android 11 webview 调用webrtc无法使用, 看logcat日志会报如下错误 [ERROR:address_tracker_linux.cc(245)] Could not send NETLINK request: Permission denied (13) 查了下相关的网络权限都有配置了还是不行&#xff0c;还是报这个权限问题 原因&#xff1…...

嵌入式单片机中晶振的工作原理

晶振在单片机中是必不可少的元器件&#xff0c;只要用到CPU的地方就必定有晶振的存在&#xff0c;那么晶振是如何工作的呢&#xff1f; 什么是晶振 晶振一般指晶体振荡器&#xff0c;晶体振荡器是指从一块石英晶体上按一定方位角切下的薄片&#xff0c;简称为晶片。 石英晶体谐…...

AWS配置内网EC2服务器上网【图形化配置】

第一种方法&#xff1a;创建EC2选择启用分配公网ip 1. 创建vpc 2. 创建子网 3. 创建互联网网关 创建互联网网关 创建互联网网关 &#xff0c;设置名称即可 然后给网关附加到新建的vpc即可 4. 给新建子网添加路由规则&#xff0c;添加新建的互联网网关然后点击保存更改 5. 新建…...

Android中的MVVM

演变 开发常用的框架包括MVC、MVP和本文的MVVM&#xff0c;三种框架都是为了分离ui界面和处理逻辑而出现的框架模式。mvp、mvvm都由mvc演化而来&#xff0c;他们不属于某种语言的框架&#xff0c;当存在ui页面和逻辑代码时&#xff0c;我们就可以使用这三种模式。 model和vie…...

制作耳机壳的UV树脂和塑料材质相比劣势有哪些?

以下是UV树脂相比塑料材质可能存在的劣势&#xff1a; 价格较高&#xff1a;相比一些常见的塑料材质&#xff0c;UV树脂的价格可能较高。这主要是因为UV树脂的生产过程较为复杂&#xff0c;需要较高的技术和设备支持。加工难度大&#xff1a;虽然UV树脂的加工过程相对简单&…...

CSP-202012-1-期末预测之安全指数

CSP-202012-1-期末预测之安全指数 题目很简单&#xff0c;直接上代码 #include <iostream> using namespace std; int main() {int n, sum 0;cin >> n;for (int i 0; i < n; i){int w, score;cin >> w >> score;sum w * score;}if (sum > 0…...

Doris中的本地routineload环境,用于开发回归测试用例

----------------2024-2-6-更新-------------- doris的routineload&#xff0c;就是从kafka中加载数据到表&#xff0c;特点是定时、周期性的从kafka取数据。 要想在本地开发测试routine load相关功能&#xff0c;需要配置kafka环境&#xff0c;尤其是需要增加routine load回…...

【开源项目阅读】Java爬虫抓取豆瓣图书信息

原项目链接 Java爬虫抓取豆瓣图书信息 本地运行 运行过程 另建项目&#xff0c;把四个源代码文件拷贝到自己的包下面 在代码爆红处按ALTENTER自动导入maven依赖 直接运行Main.main方法&#xff0c;启动项目 运行结果 在本地磁盘上生成三个xml文件 其中的内容即位爬取…...

基于opencv-python模板匹配的银行卡号识别(附源码)

目录 介绍 数字模板处理 银行卡图片处理 导入数字模板 模板匹配及结果 介绍 我们有若干个银行卡图片和一个数字模板图片&#xff0c;如下图 我们的目的就是通过对银行卡图片进行一系列图像操作使得我们可以用这个数字模板检测出银行卡号。 数字模板处理 首先我们先对数…...

JAVA设计模式之建造者模式详解

建造者模式 1 建造者模式介绍 建造者模式 (builder pattern), 也被称为生成器模式 , 是一种创建型设计模式. 定义: 将一个复杂对象的构建与表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 **建造者模式要解决的问题 ** 建造者模式可以将部件和其组装过程分开…...

ElasticSearch查询语句用法

查询用法包括&#xff1a;match、match_phrase、multi_match、query_string、term 1.match 1.1 不同字段权重 如果需要为不同字段设置不同权重&#xff0c;可以考虑使用bool查询的should子句来组合多个match查询&#xff0c;并为每个match查询设置不同的权重 {"query&…...

CasRel关系抽取实战:对接Airflow构建SPO抽取ETL调度流水线

CasRel关系抽取实战&#xff1a;对接Airflow构建SPO抽取ETL调度流水线 1. 项目背景与价值 在日常业务中&#xff0c;我们经常需要从大量文本数据中提取结构化信息。比如从新闻文章中提取人物关系&#xff0c;从产品描述中提取规格参数&#xff0c;从客服对话中提取用户诉求等…...

JAVA集成CAS客户端总结

一、依赖<dependency><groupId>org.jasig.cas.client</groupId><artifactId>cas-client-support-springboot</artifactId><version>3.6.4</version></dependency>二、yml配置cas:server-url-prefix: https://xxx.xxx:8443/cas…...

PyTorch 2.5快速部署指南:3步开启你的AI模型训练之旅

PyTorch 2.5快速部署指南&#xff1a;3步开启你的AI模型训练之旅 1. PyTorch 2.5环境准备 PyTorch 2.5作为当前最流行的深度学习框架之一&#xff0c;带来了多项性能优化和新特性。在开始之前&#xff0c;我们需要确保环境配置正确。 1.1 系统要求检查 操作系统&#xff1a…...

放弃OpenVINO!在树莓派5上用Anaconda环境直接跑通YOLOv5摄像头检测

放弃OpenVINO&#xff01;在树莓派5上用Anaconda环境直接跑通YOLOv5摄像头检测 树莓派作为嵌入式开发的明星产品&#xff0c;其第五代在性能上有了显著提升&#xff0c;4GB内存和2.4GHz四核处理器让它能够胜任更多AI推理任务。而YOLOv5作为目标检测领域的轻量级标杆&#xff0c…...

MedGemma X-Ray 场景应用:基层医生的AI辅助阅片实战指南

MedGemma X-Ray 场景应用&#xff1a;基层医生的AI辅助阅片实战指南 1. 基层医疗的痛点与AI解决方案 在基层医疗机构&#xff0c;放射科医生常常面临两大挑战&#xff1a;一是阅片经验相对不足&#xff0c;二是工作负荷过重。一张胸部X光片可能包含数十个需要观察的关键点&am…...

如何实现ElasticHQ与ElasticSearch 8.x的完美兼容:未来就绪的监控解决方案

如何实现ElasticHQ与ElasticSearch 8.x的完美兼容&#xff1a;未来就绪的监控解决方案 【免费下载链接】elasticsearch-HQ Monitoring and Management Web Application for ElasticSearch instances and clusters. 项目地址: https://gitcode.com/gh_mirrors/el/elasticsearc…...

家常饺子·每家不一样

你家的馅&#xff0c;和我家的不一样 1. 食材清单&#xff08;家家都有&#xff09; 食材分类具体材料分量备注皮面粉3碗买现成的饺子皮也行水适量和面用馅猪肉馅1斤肥瘦三七开白菜或韭菜1把看你家爱吃什么姜末一点点葱花一小把盐1勺生抽1勺香油几滴 2. 核心步骤&#xff1a;…...

STM32CubeMX定时器避坑指南:为什么你的中断总是不触发?

STM32CubeMX定时器避坑指南&#xff1a;为什么你的中断总是不触发&#xff1f; 第一次使用STM32CubeMX配置定时器中断时&#xff0c;很多开发者都会遇到一个令人抓狂的问题——代码编译下载后&#xff0c;中断就像睡着了一样毫无反应。LED灯不闪烁、串口没输出、变量不更新&…...

告别黑盒调试:为VS2022和Halcon HImage定制一个带暗色主题的视觉化调试器

为VS2022和Halcon HImage打造沉浸式暗色调试器&#xff1a;从UI优化到高效开发实践 在计算机视觉开发领域&#xff0c;Halcon凭借其强大的图像处理能力成为工业检测、医疗影像等场景的首选工具。然而&#xff0c;长时间面对传统调试界面容易导致视觉疲劳&#xff0c;影响开发效…...

OpenClaw调试技巧:QwQ-32B任务失败的根本原因分析

OpenClaw调试技巧&#xff1a;QwQ-32B任务失败的根本原因分析 1. 问题背景与诊断框架 上周我在尝试用OpenClaw对接本地部署的QwQ-32B模型时&#xff0c;遇到了一个典型问题&#xff1a;简单的文件整理任务总是执行到一半就中断&#xff0c;控制台只显示"模型响应超时&qu…...