为什么我不应该使用catch()来处理ReactuseEffectAPI调用中的错误?

在 React 文档的这个页面上:

https://reactjs.org/docs/faq-ajax.html

代码注释说...

注意:在这里处理错误而不是 catch() 块很重要,这样我们就不会吞下来自组件中实际错误的异常。

...关于在第二个参数.then之后处理错误fetch。文档中的完整片段是:

  useEffect(() => {
    fetch("https://api.example.com/items")
      .then(res => res.json())
      .then(
        (result) => {
          setIsLoaded(true);
          setItems(result);
        },
        // Note: it's important to handle errors here
        // instead of a catch() block so that we don't swallow
        // exceptions from actual bugs in components.
        (error) => {
          setIsLoaded(true);
          setError(error);
        }
      )
  }, [])

它没有详细说明这个建议,我已经看到了许多使用 React 代码catch处理 API 调用错误的例子。我试过谷歌搜索,但找不到任何说明。

有人可以更详细地解释一下为什么我不应该catch用来处理fetchuseEffect钩子中进行API 调用时出现的错误吗?

还是在某些情况下可以这样做,而在其他情况下则不然?

“在组件中吞下异常 [...]”是什么意思?

此规则/指南适用于所有 React,还是仅适用于 API 调用?

或者只是useEffect挂钩或componentDidMount生命周期方法?

回答

我能在这方面找到的所有内容似乎都可以追溯到2016年左右的这个 github 问题。我将逐字引用那里的内容,因为之前 Stack Overflow 上似乎没有介绍过它,并且它对事情的解释非常彻底:


.then(() => {
  this.setState({ loaded: true })
})
.catch(()=> { 
  console.log('Swallowed!') 
});

您的catch()处理程序将捕获then()
在它之前链中抛出的任何错误,包括render()由于
setState()调用而引起的错误。

即使您不setState直接使用,如果您调用的其他代码使用它(例如 Redux dispatch()),您也可能会遇到同样的问题。

如果您不想捕获由 引起的错误setState(),而只想捕获网络故障(假设您Promise.resolve()
实际上是 a fetch()),则您想改用第二个then()参数:

componentDidMount() {
  Promise.resolve()
  .then(() => {
      this.setState({ loaded: true })
  }, (err) => {
    console.log('An error occurred (but not in setState!)', err);
  });
}

在这种情况下,除非你catch()在链的后面,否则错误
render()将不会被捕获,并且使用良好的 Promise polyfill(或在 Chrome 和其他浏览器中使用本机 Promises)显示。


编辑:按照@Martin 的回答,我去测试了这个,我可以确认这似乎不再是一个相关的问题。setState从 v16.0 开始,任何版本的 React 都不会捕获来自 的渲染错误,并且由于useState仅在 v16.8 中引入,这似乎不可能成为钩子的问题。

这是一个代码沙盒,它演示了旧版 React 中的原始问题。


回答

这是示例作者的复制粘贴错误。第一个示例使用基于类的组件的组件状态:this.setState()导致同步重新渲染(或者至少在 2016 年的 react v15.0 中是这种情况,不确定今天是否适用)。因此,警告注释和第二个 arg to 的使用.then(onResolve, onReject)是合理的。第二个例子使用了useState一个函数组件的钩子:setState导致没有同步重新渲染,只有异步重新渲染。因此警告注释,使用第二arg的到.then(onResolve, onReject)没有道理的。

为了说明这一点:使用useState钩子,您可以调用多个更新程序,并且它们都只会在一次重新渲染时生效。

const [a, setA] = useState();
const [b, setB] = useState();
const [c, setC] = useState();

const updateState = () => {
  setA('foo');
  setB('bar');
  setC('buz');
  // will only cause one single re-render
}

因此使用 catch 完全没问题

useEffect(() => {
    fetch("https://api.example.com/items")
      .then(res => res.json())
      .then(
        (result) => {
          setIsLoaded(true);
          setItems(result);
        }
      )
      .catch(
        (error) => {
          setIsLoaded(true);
          setError(error);
        }
      )
  }, [])


以上是为什么我不应该使用catch()来处理ReactuseEffectAPI调用中的错误?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>