如何捕获子组件的事件处理程序中抛出的错误?

时间:2021-07-09 03:18:19

标签: reactjs

有两个功能组件。在点击事件处理程序 doStuff 中抛出了一个未知和意外的错误。 意外意味着我不能像往常一样使用 try...catch... 语句。

我已阅读 Error Boundaries,但它似乎只适用于基于类的组件。

我怎样才能发现错误并从这种情况中恢复过来?

附加上下文:我无法修改 Child 组件的代码。

import React from 'react';

function Child() {
  function doStuff() {
    throw new Error('An unknown and unexpected error from somewhere');
  }

  return <p onClick={doStuff}>my-button</p>;
}

function Parent() {
  // How to catch the click event handler error in parent
  return <Child></Child>;
}

2 个答案:

答案 0 :(得分:1)

我不确定您对 I can't use the try...catch... statement as usual 的意思。我会使用一个可以捕获错误的委托函数。

function Child() {
  function doStuff() {
    throw new Error('An unknown and unexpected error from somewhere');
  }

  function tryDoStuff(){
    try {
      doStuff()
    } catch (e) {
      console.log("Caught: " + e);
    }
  }
  
  return <button onClick={tryDoStuff} className="btn btn-primary">my-button</button>;
}

function Parent() {
  // How to catch the click event handler error in parent
  return <Child></Child>;
}

ReactDOM.render(<Parent/>, document.getElementById("root"));
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

答案 1 :(得分:1)

我认为你可以像这样创建错误边界钩子

const CatchErrorContext = React.createContext({});

function withCatchError(Component) {
  return class extends React.Component {
    componentDidCatch(error, errorInfo) {
      this.setState({ error, errorInfo });
    }

    render() {
      return (
        <CatchErrorContext.Provider value={{ ...this.state }}>
          <Component {...this.props} />
        </CatchErrorContext.Provider>
      );
    }
  };
}

function useCatchError() {
  return useContext(CatchErrorContext);
}

然后,你可以使用

const Parent = withCatchError(() => {
  const { error } = useCatchError();

  if (error) return <div>Some error</div>
  return ...
})

错误边界无法捕获每个错误。它只能捕获渲染错误。如果你想捕获所有的错误,你可以这样做

function useCatchGlobalError() {
  const [error, setError] = useState(null);

  useEffect(() => {
    const errorHandler = (e) => {
      setError(e);
      return true;
    };

    window.addEventListener("error", errorHandler);
    return () => window.removeEventListener("error", errorHandler);
  }, []);

  return error;
}

然后你就可以使用

function Parent() {
  const error = useCatchGlobalError();
  ...
}