使用 React 18 和 Suspense,如何显示特定错误,而不仅仅是 ErrorBoundary 中的回退

Pet*_*ner 5 reactjs react-suspense swr

我有一个像这样结构的组件,并ErrorBoundary包装了我的Suspense元素。

function App() {
  return (
    <ErrorBoundary fallback={<h2>Could not fetch cities.</h2>}>
      <Suspense fallback={<div>Loading..</div>}>
        <MyList />
      </Suspense>
    </ErrorBoundary>
  );
}
Run Code Online (Sandbox Code Playgroud)

MyList组件包含一个SWR数据获取钩子,如下所示:

const { data } = useSwr(`/api/mydata`, fetcher, {
      suspense: true,
    });
Run Code Online (Sandbox Code Playgroud)

我的 fetcher 方法抛出错误,如下所示:

  const rsp = await fetch(url);
  if (rsp.ok) {
    return await rsp.json();
  } else {
    const MyError = function (message, status) {
      this.message = `${message} from url ${url} status code:${status}`;
      this.status = status;
    };
    throw new MyError(rsp.statusText, rsp.status);
  }
}
Run Code Online (Sandbox Code Playgroud)

当错误发生时,我不知道如何让我的 UI 显示抛出的值(即 MyError 类中的内容)

Pet*_*ner 0

这是我一直在寻找的答案:

fetcher.js

export async function fetcher(url) {
  const rsp = await fetch(url);
  if (rsp.ok) {
    return await rsp.json();
  } else {
    const MyError = function (message, status) {
      this.message = `${message} from url ${url} status code:${status}`;
      this.status = status;
    };
    throw new MyError(rsp.statusText, rsp.status);
  }
}
Run Code Online (Sandbox Code Playgroud)

错误边界.js

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

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

  render() {
    function addExtraProps(Component, extraProps) {
      return <Component.type {...Component.props} {...extraProps} />;
    }

    if (this.state.hasError) {
      return addExtraProps(this.props.fallback, {
        errorMessage: this.state.message,
        errorStatus: this.state.status,
      });
    }
    return this.props.children;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后用法是这样的:

function CityLayout(props) {
  const { setSelectedCityId } = useContext(CityContext);
  return (
    <>
      <CityListMaxDDL />
      <CityList displayCount={5} />
      <CityDetail cityId={setSelectedCityId} />
    </>
  );
}

function App() {
  function MyErrorBoundaryFallback({ errorMessage, errorStatus }) {
    return (
      <div className="container">
        <h1>Error</h1>
        <div className="row">
          Error Status: <b>{errorStatus}</b>
        </div>
        <div className="row">
          ErrorMessage: <b>{errorMessage}</b>
        </div>
      </div>
    );
  }

  return (
    <ErrorBoundary fallback={<MyErrorBoundaryFallback />}>
      <Suspense fallback={<div>Loading..</div>}>
        <div className="container">
          <CityProvider>
            <CityLayout />
          </CityProvider>
        </div>
      </Suspense>
    </ErrorBoundary>
  );
Run Code Online (Sandbox Code Playgroud)