如何避免componentDidCatch()多次触发?

时间:2018-08-27 15:11:52

标签: javascript reactjs

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

我的第一步虽然是保存自己的prevError状态,然后检查传递给error的{​​{1}}是否相同。但这是行不通的,因为componentDidCatch()请求不是立即请求。其他一些生命周期事件通过了最新状态,但事实并非如此。我知道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()内)?


我的意思的完整React示例:

logErrorToMyService
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>切换到类中的字段之外,我还将其更改为数组,以便重复错误-但这可能两者之间的不同错误也将被跳过。

1 个答案:

答案 0 :(得分:1)

在您发布的代码中,Foo.Web2/wwwroot/assets会在第一时间运行componentDidCatch()回调之前迅速连续触发大约十二次。但是,setstate不必是prevError的一部分,因为它与组件的外观无关。

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