Bug: ErrorBoundary won't caught error in useEffect callback while ErrorBoundary unmount with it's children

This issue has been tracked since 2022-09-06.

React version: 18.2.0

Steps To Reproduce

function App() {
  const [isShow, setIsShow] = React.useState(true);
  function setError() {
  return (
      {isShow && <PageWrapper />}
      <div onClick={setError}>setError</div>

class PageWrapper extends React.Component {
  static getDerivedStateFromError() {}
  componentDidCatch(err) {
    console.log("catch err: ", err);
  render() {
    return <Page />;

function Page() {
  React.useEffect(() => {
    return () => {
      throw new Error("sorry!");
  return <div>I m page</div>;

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />)
  1. click setError.Unmount <PageWrapper> along with <Page>, then <Page> threw an error in useEffect callback.

The current behavior

ErrorBoundary <PageWrapper> won't caught error thrown by <Page> useEffect callback.So all the React Tree is dropped.

But in React 17, <PageWrapper> caught the error.And the React Tree remain exists.

The expected behavior

Catch the error like React 17.

So, is that React18 new behavior? Or is a bug?

sadiki-o wrote this answer on 2022-09-06

can you please tell me why are you mixing class components with function components?

Chen-jj wrote this answer on 2022-09-06


Because ErrorBoundary only work with class components.

sadiki-o wrote this answer on 2022-09-06

oh my apology since i worked mostly with function components i never get to use such feature

creamidea wrote this answer on 2022-09-13

This may be related to the change in the commitRoot phase traversal. v17 traverses the effect list. v18 traverses the entire tree.
When dealing with PassiveUnmountEffects, the connection to child is removed. v18 does not have a way to call PageWrapper's Page's destroy, while v17 can handle the destroy function through the effect list.

creamidea wrote this answer on 2022-09-14

Maybe I find the problem, here is set skipUnmountedBoundaries to be true.

if (skipUnmountedBoundaries) {

So, the compiler's output




// This rolled out to 10% public in www, so we should be able to land, but some

// This rolled out to 10% public in www, so we should be able to land, but some
// internal tests need to be updated. The open source behavior is correct.
export const skipUnmountedBoundaries = true;
More Details About Repo
Owner Name facebook
Repo Name react
Full Name facebook/react
Language JavaScript
Created Date 2013-05-24
Updated Date 2022-10-05
Star Count 195628
Watcher Count 6648
Fork Count 40518
Issue Count 1111


Issue Title Created Date Updated Date