wordpress建站哪里好,设计企业网站多少钱,欧美设计网站推荐,简述创建一个网站的过程文章目录 捕获错误 hook创建错误边界组件 Provider定义错误边界组件定义边界组件状态捕捉错误渲染备份组件重置组件通过 useHook 控制边界组件 捕获错误 hook
getDerivedStateFromError 返回值会作为组件的 state 用于展示错误时的内容 componentDidCatch
创建错误边界组件 P… 文章目录 捕获错误 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 createContextErrorBoundaryContextType | 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 ComponentErrorBoundaryProps,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 ComponentErrorBoundaryProps,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 ComponentErrorBoundaryProps,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;// Theres an edge case where if the thing that triggered the error happens to *also* be in the resetKeys array,// wed end up resetting the error boundary immediately.// This would likely trigger a second error to be thrown.// So we make sure that we dont 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 UseErrorBoundaryStateTError | { error: TError; hasError: true }| { error: null; hasError: false };export type UseErrorBoundaryApiTError {resetBoundary: () void;showBoundary: (error: TError) void;
};export function useErrorBoundaryTError any(): UseErrorBoundaryApiTError {// 获取最近的边界组件 Provider 的内容const context useContext(ErrorBoundaryContext);// 断言 Context 是否为空assertErrorBoundaryContext(context);const [state, setState] useStateUseErrorBoundaryStateTError({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;
}