Skip to content

Commit 43647c6

Browse files
manudeliLineGu
andcommitted
fix(react): prevent rendering fallback if not shouldCatch error
Co-authored-by: lucas0530 <[email protected]> Co-authored-by: HYUNGU KANG <[email protected]>
1 parent 07b6b77 commit 43647c6

File tree

6 files changed

+60
-8
lines changed

6 files changed

+60
-8
lines changed

examples/visualization/src/app/layout.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ export default function RootLayout({ children }: { children: React.ReactNode })
3131
<li>
3232
<Link href="/react/ErrorBoundary/shouldCatch">{`<ErrorBoundary/>`} shouldCatch prop</Link>
3333
</li>
34+
<li>
35+
<Link href="/react/ErrorBoundary/shouldCatch/renderPhase">
36+
{`<ErrorBoundary/>`} shouldCatch prop render phase
37+
</Link>
38+
</li>
3439
<li>
3540
<Link href="/react/zodSearchParams">zod: no param</Link>
3641
</li>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'use client'
2+
3+
import { ErrorBoundary } from '@suspensive/react'
4+
import { Throw } from '~/components/Throw'
5+
6+
export default function page() {
7+
return (
8+
<ErrorBoundary fallback={() => <>root fallback</>}>
9+
<ErrorBoundary
10+
shouldCatch={(error) => error.message !== 'children error message'}
11+
fallback={() => {
12+
console.log("child ErrorBoundary's fallback")
13+
return <>child ErrorBoundary's fallback</>
14+
}}
15+
>
16+
<Throw.Error message="children error message" after={2000}>
17+
before throw Error
18+
</Throw.Error>
19+
</ErrorBoundary>
20+
</ErrorBoundary>
21+
)
22+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { type PropsWithChildren, useState } from 'react'
2+
import { useTimeout } from '~/hooks'
3+
4+
export const Throw = {
5+
Error: ({ message, after = 0, children }: PropsWithChildren<{ message: string; after?: number }>) => {
6+
const [isNeedThrow, setIsNeedThrow] = useState(after === 0)
7+
if (isNeedThrow) {
8+
throw new Error(message)
9+
}
10+
useTimeout(() => setIsNeedThrow(true), after)
11+
return <>{children}</>
12+
},
13+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { useTimeout } from './useTimeout'
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { useCallback, useEffect, useRef } from 'react'
2+
3+
export const useTimeout = (fn: () => void, ms: number) => {
4+
const fnRef = useRef(fn)
5+
fnRef.current = fn
6+
const fnPreserved = useCallback(() => fnRef.current(), [])
7+
useEffect(() => {
8+
const id = setTimeout(fnPreserved, ms)
9+
return () => clearTimeout(id)
10+
}, [fnPreserved, ms])
11+
}

packages/react/src/ErrorBoundary.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,6 @@ class BaseErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState
118118
if (error instanceof SuspensiveError) {
119119
throw error
120120
}
121-
const { shouldCatch = true } = this.props
122-
const isCatch = Array.isArray(shouldCatch)
123-
? shouldCatch.some((shouldCatch) => checkErrorBoundary(shouldCatch, error))
124-
: checkErrorBoundary(shouldCatch, error)
125-
if (!isCatch) {
126-
throw error
127-
}
128121
this.props.onError?.(error, info)
129122
}
130123

@@ -134,12 +127,19 @@ class BaseErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState
134127
}
135128

136129
render() {
137-
const { children, fallback } = this.props
130+
const { children, fallback, shouldCatch = true } = this.props
138131
const { isError, error } = this.state
139132

140133
let childrenOrFallback = children
141134

142135
if (isError) {
136+
const isCatch = Array.isArray(shouldCatch)
137+
? shouldCatch.some((shouldCatch) => checkErrorBoundary(shouldCatch, error))
138+
: checkErrorBoundary(shouldCatch, error)
139+
if (!isCatch) {
140+
throw error
141+
}
142+
143143
if (typeof fallback === 'undefined') {
144144
if (process.env.NODE_ENV === 'development') {
145145
console.error('ErrorBoundary of @suspensive/react requires a defined fallback')

0 commit comments

Comments
 (0)