如何从错误边界恢复中重置 React 状态?

How to reset React state from an error boundary recovery?

我的应用程序有一个用户输入查询以向 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>
  );
};

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

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

The simplest way to use is to wrap it around any component that may throw an error. This will handle errors thrown by that component and its descendants too.

在您的示例中,抛出错误的组件是呈现 ErrorBoundary 的组件。但是为了让它工作,抛出错误的组件应该是 ErrorBoundary.

的子组件

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