Can someone explain the following weird error catching behavior by React's error boundaries (see code comments)?
import { FunctionComponent, useEffect, useRef, useState } from "react";
const Weird: FunctionComponent = () => {
const [version, setVersion] = useState<number>(0);
const renderCount = useRef<number>(0);
const condition = useRef<number>(0);
console.info(`renderCount=${renderCount.current++}, version=${version}, condition=${condition.current}`);
useEffect(() => {
const id: NodeJS.Timeout = setTimeout(() => setVersion(i => i + 1), 1_000);
return () => clearTimeout(id);
}, []);
// How to test this example:
// 1. run the code and observe that it works as expected: the error boundary catches the exception
// 2. change 'errorBoundaryCatchesError' to 'false'
// 3. comment throwing line marked with "scenario a" below
// 4. uncomment the throwing line marked with "scenario b" below
// 5. run the code again to observe that the exception does not get caught by the error boundary anymore
const errorBoundaryCatchesError: boolean = true;
if (version === 1) {
const testCondition: number = errorBoundaryCatchesError ? 1 : 0;
if (condition.current++ === testCondition) {
// scenario b - true branch
// throw new Error("ignored error");
} else {
// scenario a - false branch
throw new Error("caught error");
}
}
return <div>Hello</div>;
}
export default Weird;
In other words, if an error is thrown conditionally in the true branch of a the timeout-triggered render, it does not get caught, but if it is on the false branch, it works as expected...
The above component is wrapped into an error boundary in its parent component as follows:
<ErrorBoundary>
<Weird />
</ErrorBoundary>
The error boundary itself is a standard implementation as per Catching rendering errors with an error boundary