首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >响应查询错误边界:如何根据用户是否第二次看到组件给出不同的选项

响应查询错误边界:如何根据用户是否第二次看到组件给出不同的选项
EN

Stack Overflow用户
提问于 2021-11-14 11:25:08
回答 1查看 1.3K关注 0票数 0

我正在努力改进使用react-query的应用程序中的错误处理。

我有一个用于经过身份验证的用户路由器的<ErrorBoundary>组件:

代码语言:javascript
复制
<ErrorBoundaryRoot errorMessage="auth error">
  <PracticeTypeContextProvider>
    <IonReactRouter>
       ... myRoutesAndStuff

组件包装器如下所示:

代码语言:javascript
复制
import { ErrorBoundary } from 'react-error-boundary';

const ErrorBoundaryRoot: React.VFC<MyProps> = ({ children, errorMessage }: MyProps) => {
  const { reset } = useQueryErrorResetBoundary();

  return (
    <ErrorBoundary
      onReset={reset}
      fallbackRender={({ resetErrorBoundary }) => (
        <PageError errorMessage={errorMessage} resetErrorBoundary={resetErrorBoundary} />
      )}
    >
      <Suspense fallback={<LoadingApp />}>
        { children }
      </Suspense>
    </ErrorBoundary>
  );
};

这是正确的捕捉错误,太好了!

现在,我想向用户展示两个按钮中的一个:

如果这是第一次看到错误边界,

  • <ButtonInvalidateAuthQueries>,这样我就可以在不注销用户的情况下重新设置应用程序。
  • 但是,如果失败,我想给用户显示一个不同的按钮<ButtonResetApp>,它重置所有查询并将用户注销。

我像这样设置我的<PageError>组件:

代码语言:javascript
复制
const PageError: React.VFC<MyProps> = ({ errorMessage, resetErrorBoundary }: MyProps) => {
  const [alreadyTriedItOnce, setAlreadyTriedItOnce] = useState(false);
  return (
    <IonPage>
      <IonContent>
        <>
          { alreadyTriedItOnce ? (
            <ButtonResetApp platform={platform} resetErrorBoundary={resetErrorBoundary} />
          ) : (
            <ButtonInvalidateAuthQueries
              setAlreadyTriedItOnce={setAlreadyTriedItOnce}
              resetErrorBoundary={resetErrorBoundary}
            />
          )}
        </>
        )}
      </IonContent>
    </IonPage>
  );
};

而无效按钮:

代码语言:javascript
复制
const ButtonInvalidateAuthQueries: React.VFC<MyProps> = (
  { setAlreadyTriedItOnce, resetErrorBoundary }: MyProps,
) => {
  const queryClient = useQueryClient();
  return (
    <IonButton
      onClick={() => {
        queryClient.invalidateQueries(queryKeyInvalidateAllAuthQueries);
        resetErrorBoundary();
        setAlreadyTriedItOnce(true);
      }}
    >
      Reset auth queries
    </IonButton>
  );
};

但是,这不起作用,因为当用户单击<ButtonInvalidateAuthQueries>时,所有auth组件都会重新呈现,包括错误边界,因此如果再次显示错误边界,则将alreadyTriedItOnce状态初始化为false。

因此,我的问题是:是否有什么聪明的方法来判断<ButtonInvalidateAuthQueries>是否失败,如果是的话,则显示<ButtonResetApp>吗?

作为一种解决办法,我可以同时显示两个按钮,并给用户“先单击这个按钮,如果这个按钮不起作用,单击另一个按钮”的指令,但是我觉得作为一个程序员,我的职责是在任何给定的时间给用户最好的选择。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-16 01:49:44

通过使用上下文,我根据Bergi的评论成功地修复了这个问题。

首先,我创建了一个简单的上下文来存储布尔useState:

代码语言:javascript
复制
import React from 'react';
import useStateBoolean from '../utils/hooks/useStateBoolean';

const ErrorTriedAlreadyContext = React.createContext(false);
const ErrorTriedAlreadySetContext = React.createContext(
  {} as React.Dispatch<React.SetStateAction<boolean>>,
);

interface MyProps {
  children: JSX.Element,
}

export const ErrorTriedAlreadyContextProvider: React.VFC<MyProps> = ({ children }: MyProps) => {
  const [triedAlready, setTriedAlready] = useStateBoolean();

  return (
    <ErrorTriedAlreadyContext.Provider value={triedAlready}>
      <ErrorTriedAlreadySetContext.Provider value={setTriedAlready}>
        {children}
      </ErrorTriedAlreadySetContext.Provider>
    </ErrorTriedAlreadyContext.Provider>
  );
};

export const useErrorAlreadyTriedContext = (): [
  boolean, React.Dispatch<React.SetStateAction<boolean>>,
] => {
  const triedAlready = React.useContext(ErrorTriedAlreadyContext);
  const setTriedAlready = React.useContext(ErrorTriedAlreadySetContext);

  if (!setTriedAlready) {
    throw new Error('The ErrorTriedAlreadyProvider is missing.');
  }

  return [triedAlready, setTriedAlready];
};

然后,我创建了一个新的ErrorBoundary:

代码语言:javascript
复制
const ErrorBoundaryAuth: React.VFC<MyProps> = ({ children }: MyProps) => {
  const { reset } = useQueryErrorResetBoundary();

  return (
    <ErrorTriedAlreadyContextProvider>
      <ErrorBoundary
        onReset={reset}
        fallbackRender={({ resetErrorBoundary }) => (
          <PageError
            errorMessage={t({ id: 'error.auth_router_query_error', message: 'Temporary app error' })}
            allowAuthReset
            resetErrorBoundary={resetErrorBoundary}
          />
        )}
      >
        <Suspense fallback={<LoadingApp />}>
          { children }
        </Suspense>
      </ErrorBoundary>
    </ErrorTriedAlreadyContextProvider>
  );
};

我把它添加到我的路由器:

代码语言:javascript
复制
  return (
    <ErrorBoundaryAuth>
      <PracticeTypeContextProvider>
        <IonReactRouter>

我的纽扣:

代码语言:javascript
复制
const ButtonInvalidateAuthQueries: React.VFC<MyProps> = (
  { resetErrorBoundary }: MyProps,
) => {
  const queryClient = useQueryClient();
  const [, setAlreadyTried] = useErrorAlreadyTriedContext();
  return (
    <>
      <IonButton
        onClick={() => {
          queryClient.invalidateQueries(queryKeyInvalidateAllNonCookieQueries);
          if (resetErrorBoundary) {
            resetErrorBoundary();
          }
          // The context may not always be available.
          if (setAlreadyTried) {
            setAlreadyTried(true);
          }
        }}
      >
        <IonIcon icon={sync} slot="start" />
        <Trans id="button.reset_queries">Try again</Trans>
      </IonButton>
    </>
  );
};

现在起作用了!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69962506

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档