如何在Typescript中正确地编写React ErrorBoundary类组件?

19

这是我目前尝试如何在Typescript中正确编写React ErrorBoundary类组件的方法:

import React from "react";
import ErrorPage from "./ErrorPage";
import type { Store } from "redux";   // I'M PASSING THE REDUX STORE AS A CUSTOM PROP

interface Props {
  store: Store         // THIS IS A CUSTOM PROP THAT I'M PASSING
}

interface State {      // IS THIS THE CORRECT TYPE FOR THE state ?
  hasError: boolean
}

class ErrorBoundary extends React.Component<Props,State> {
  
  constructor(props: Props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error): State {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo: React.ErrorInfo): void {
    // You can also log the error to an error reporting service
    // logErrorToMyService(error, errorInfo);
    console.log("error: " + error);
    console.log("errorInfo: " + JSON.stringify(errorInfo));
    console.log("componentStack: " + errorInfo.componentStack);
  }

  render(): React.ReactNode {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return(
        <ErrorPage
          message={"Something went wrong..."}
        />
      );
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

这个问题是关于ErrorBoundary类组件的类型。我将其分成几部分以使其更易于理解。


第一部分:props和state的类型

我的做法正确吗?

interface Props {
  store: Store         // THIS IS A CUSTOM PROP THAT I'M PASSING
}

interface State {      // IS THIS THE CORRECT TYPE FOR THE state ?
  hasError: boolean
}

class ErrorBoundary extends React.Component<Props,State> {}

第二部分:getDerivedStateFromError(error)

error参数中,我应该选择哪种类型?返回类型应该是State类型,对吗?

static getDerivedStateFromError(error): State {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

第三部分:componentDidCatch(error, errorInfo: React.React.ErrorInfo)

error参数中应选择什么类型?对于errorInfo,React确实有一个ErrorInfo类型似乎是正确的。对吗?返回类型应该是void,对吗?

componentDidCatch(error, errorInfo: React.ErrorInfo): void {
    console.log("error: " + error);
    console.log("errorInfo: " + JSON.stringify(errorInfo));
    console.log("componentStack: " + errorInfo.componentStack);
}

第 D 部分:render() 方法

返回类型应该是 ReactNode 吗?

render(): React.ReactNode {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return(
        <ErrorPage
          message={"Something went wrong..."}
        />
      );
    }

    return this.props.children;
  }

这个语法是否被允许:import type { Store } from "redux";? - captain-yossarian from Ukraine
@captain-yossarian 是的,它似乎运行得很好。但是 import type 语法是在较新版本的Typescript中发布的,不确定是哪个版本,但在一些旧版本中无法使用。 - cbdeveloper
你应该将redux store传递给<Provider store={store}>,而不是直接传递给你的组件。 - captain-yossarian from Ukraine
我也在做这件事。但不是针对ErrorBoundary。但我猜我可以通过react-redux中的useStore()访问存储,因为ErrorBoundary将在<Provider store={store}>内部。谢谢。编辑:实际上我不能在类组件中使用useStore。刚发现了那个错误信息:React Hook“useStore”不能在类组件中调用。React Hooks必须在React函数组件或自定义React Hook函数中调用。 - cbdeveloper
PART C: 此成员必须具有“override”修饰符,因为它覆盖了基类'Component<Record<string, never>, ErrorBoundaryState, any>'中的成员。.ts(4114)PART D: 此成员必须具有“override”修饰符,因为它覆盖了基类'Component<Record<string, never>, ErrorBoundaryState, any>'中的成员。.ts(4114) - Kmylo darkstar
2个回答

21

您可以将以下代码用作错误边界

import React, { Component, ErrorInfo, ReactNode } from "react";

interface Props {
  children: ReactNode;
}

interface State {
  hasError: boolean;
}

class ErrorBoundary extends Component<Props, State> {
  public state: State = {
    hasError: false
  };

  public static getDerivedStateFromError(_: Error): State {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    console.error("Uncaught error:", error, errorInfo);
  }

  public render() {
    if (this.state.hasError) {
      return <h1>Sorry.. there was an error</h1>;
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

4
你可以在@types/reactindex.d.ts文件中找到所有答案。如果你使用像VSCode这样的IDE,你可以通过Ctrl +点击类型直接跳转到其定义。
以下是你问题的精确答案,但在此之前,请让我建议你优先使用React的hooks而不是类。

编辑者注: 我从不使用类组件,总是更喜欢函数和钩子(hooks),但来自React 文档 关于错误边界(Error Boundaries)的说明如下:

错误边界(Error boundaries)的工作方式类似于JavaScript中的 catch {} 块,但是针对的是组件。 只有类组件可以作为错误边界。


我提供的内容来自版本16.9.49的index.d.ts文件。

A部分: 是的,那就是正确的方法。

B部分: 正如您在第658行所看到的,error的类型为any,返回类型是state的部分或null

C部分: 在第641行,您会看到error的类型为Error,返回类型为void

D部分: 在第494行,您可以看到渲染应返回一个ReactNode...


1
谢谢,伙计。我现在正在查看类型定义文件。我忘记了这些方法签名会在类型定义文件中。我决定在 getDerivedStateFromError(error) 中使用 unknown 代替 any 来表示 error 参数。 - cbdeveloper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接