如果某个组件渲染了10次,并且有错误,则componentDidCatch()将因相同的错误触发10次。目前,我正在捕获一个API请求以记录该错误,但是我只希望将该错误记录一次。

我的第一个操作是将自己的prevError保存为状态,并检查传递给errorcomponentDidCatch()是否相同。但这是行不通的,因为setState请求不是立即发出的。其他一些生命周期事件通过了最新状态,但事实并非如此。我知道setState()接受具有最新状态的回调,但是到那时错误将始终等于prevError。这就是我的意思:

componentDidCatch(error, info) {
    this.setState({ error: true });

    const isNewError = (error.toString() !== this.state.prevError.toString());
    // always true since setState is async
    if (isNewError) {
       logErrorToMyService(error, info); // should only run once
       this.setState({ prevError: error });
    }
}


我也不认为我可以使用componentDidUpdate(),因为那不知道我的错误。

我想念什么吗?我是在错误地处理此问题,是否需要对其进行重新处理(也许将支票移到logErrorToMyService中)?



我的意思的完整React示例:



const logErrorToMyService = () => console.warn('I should only be run once');

class ErrorBoundary extends React.Component {
  state = {
    error: false,
    prevError: new Error(),
  }

  componentDidCatch(error, info) {
    this.setState({ error: true });

    // none of the below code will work correctly
    const isNewError = (error.toString() !== this.state.prevError.toString());
    // always true since setState is async
    if (isNewError) {
       logErrorToMyService(error, info); // should only run once
       this.setState({ prevError: error });
    }
  }

  render() {
    if (this.state.error) {
      return <div>Something went (purposefully) wrong.</div>;
    }
    return this.props.children;
  }
}

// below is 10 purposefully buggy component instances
const BuggyComponent = () => (
    <div>{purposefully.throwing.error}</div>
)

const App = () => (
  <ErrorBoundary>
    {[...Array(10)].map((_, i) => <BuggyComponent key={i} />)}
  </ErrorBoundary>
)

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

<div id='root'></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.3.1/umd/react-dom.development.js"></script>







更新:除了将prevError切换到类中的字段之外,我还将其更改为数组,从而也可以跳过重复错误-但两者之间可能有不同的错误。

最佳答案

在您发布的代码中,componentDidCatch()将迅速连续触发大约十二次,这要早于setstate回调首次运行之前。但是prevError不必是state的一部分,因为它与组件的外观无关。

只需将其实现为类变量,即可同步设置。

关于javascript - 如何避免componentDidCatch()多次触发?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52042251/

10-08 23:24