【问题标题】:How to reset React state from an error boundary recovery?如何从错误边界恢复中重置 React 状态?
【发布时间】:2021-03-27 02:50:25
【问题描述】:

我的应用程序有一个用户输入查询以向 Pokemon API 发出请求并呈现响应数据。

如果用户输入数据库中不存在的查询,它将触发错误边界和Try Again 按钮,通过重置查询状态从错误中恢复并让用户重新提交不同的查询。这是预期的行为。

但是,在我当前的设置下,当用户的查询没有任何匹配项时,控制台将显示GET https://pokeapi.co/api/v2/pokemon/foo 404Uncaught (in promise) Error: Request failed with status code 404。但是,用户没有看到此错误。没有什么可以告诉用户他们的查询没有任何匹配项。我的目标是获得更明确的用户体验,告诉用户他们提交的请求没有任何匹配项,然后单击 Try Again 按钮重置输入并提交新查询。我相信,这就是错误边界应该做的。

我正在使用以下库:React Query, React Hook Form, React Error Boundary。有人建议我使用 React Query 的 onError 回调来记录错误并设置属性 useErrorBoundary: true。还是没有运气。

这是一个演示预期行为的工作示例。 https://epic-react-exercises.vercel.app/react/hooks/3

这是我的尝试。请让我知道如何解决这个问题。 https://codesandbox.io/s/pokedex-5j1jf

const ErrorFallback = ({ error, resetErrorBoundary }) => {
  return (
    <div role="alert">
      <p>Something went wrong:</p>
      <pre style={{ color: "red" }}>{error.message}</pre>
      <button onClick={resetErrorBoundary}>Try again</button>
      <p>This error was caught by the error boundary!</p>
    </div>
  );
};

const searchSchema = yup.object().shape({
  pokemonName: yup.string().required()
});

const App = () => {
  const [query, setQuery] = useState("");
  const [pokemonCharacter, setPokemonCharacter] = useState({});
  const { register, handleSubmit, watch, errors } = useForm({
    resolver: yupResolver(searchSchema)
  });

  const handlePokemonFetch = () => {
    return axios(`https://pokeapi.co/api/v2/pokemon/${query}`).then((res) => {
      setPokemonCharacter(res.data);
    });
  };

  const { loading, error } = useQuery("pokemon", handlePokemonFetch, {
    refetchOnWindowFocus: false,
    enabled: false,
    useErrorBoundary: true,
    onError: (error) => console.log(error)
  });

  console.log(watch(pokemonCharacter));

  return (
    <div>
      <div>
                <form onSubmit={handleSubmit(handlePokemonFetch)}>
                    <label htmlFor="Pokemon">Pokémon Character</label>
                    <input
                        type="text"
                        name="pokemonName"
                        ref={register}
                        onChange={(event) => setQuery(event.target.value)}
                    />
                    {errors.pokemonName && <span>This field is required</span>}
                    {error && <p>Error occurred: {error.message}</p>}
                    <button type="submit">Search Pokémon</button>
                </form>
      </div>
            <ErrorBoundary
        FallbackComponent={ErrorFallback}
        onReset={() => {
          setQuery("");
        }}
        resetKeys={[query]}
      >
        <div>
          {loading && <p>Loading...</p>}
          <PokemonInfo pokemonCharacter={pokemonCharacter} />
        </div>
      </ErrorBoundary>
            <ReactQueryDevtools initialIsOpen={true} />
    </div>
  );
};

【问题讨论】:

  • 请在您的问题正文中发布一组最小化的工作代码。将来,您的链接可能不再有效,因此我们希望该问题能够独立存在。
  • @y2bd 没问题,我刚刚添加了代码。
  • 不能在handlePokemonFetch 中的.catch 语句中处理吗?
  • @WebbH React-Query 期望一个失败的承诺,所以没有 catch 方法,因为它将使它成为一个已解决的承诺。

标签: reactjs react-hooks react-hook-form react-query react-error-boundary


【解决方案1】:

我认为问题出在您使用错误边界的方式上。

如果我们查看 react-error-boundary 的文档,我们会看到以下内容:

最简单的使用方法是将它包裹在任何可能引发错误的组件周围。这也将处理该组件及其后代抛出的错误。

在您的示例中,引发错误的组件是呈现ErrorBoundary 的组件。但为了使其正常工作,引发错误的组件应该是 ErrorBoundary 的子组件。

我创建了一个稍微不同的沙箱来说明这一点。 https://codesandbox.io/s/jovial-poincare-06e6v

【讨论】:

  • 谢谢你的例子。请检查更新的 Codesandbox,因为我实施了您的建议。但是,它不适用于我的代码设置方式。
  • 您在更新的沙箱中遗漏了一些东西: 1. useQuery 挂钩必须在 组件中使用。 2)您强制调用 handlePokemonFetch 函数。 3)你的useQuery钩子没有被使用,因为启用:false。
  • 你需要做的是将useQuery钩子移到SearchForm里面,然后onSubmt去setQuery,只有在query不为空的时候才启用useQuery钩子​​span>
  • 感谢您一直以来的帮助。我将useQuery 逻辑移动到。对于您的建议,我删除了enabled:false。我最初将它设置在那里是为了防止在安装时运行查询。抱歉,您能否澄清onSubmt to setQuery 的意思。我再次更新了代码框。
  • 您不是使用useQuery 获取数据,而是直接调用handlePokemonFetch 函数。看看我的示例,了解如何正确使用 enabled 属性仅在用户输入内容后触发提取
猜你喜欢
  • 1970-01-01
  • 2018-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-15
  • 1970-01-01
  • 2020-04-26
  • 1970-01-01
相关资源
最近更新 更多