From 5e08d23fba28c66c548627f7d19329ca590f088b Mon Sep 17 00:00:00 2001 From: Jonghyeon Ko Date: Mon, 6 Jan 2025 22:37:05 +0900 Subject: [PATCH 1/9] feat(react): prevent recursive expose fallback when fallback throw error --- packages/react/src/ErrorBoundary.spec.tsx | 22 +++++++++++++++ packages/react/src/ErrorBoundary.tsx | 34 +++++++++++++++++++---- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/packages/react/src/ErrorBoundary.spec.tsx b/packages/react/src/ErrorBoundary.spec.tsx index cbcf8ded0..8132526d2 100644 --- a/packages/react/src/ErrorBoundary.spec.tsx +++ b/packages/react/src/ErrorBoundary.spec.tsx @@ -293,6 +293,28 @@ describe('', () => { await waitFor(() => expect(screen.queryByText(errorText)).toBeInTheDocument()) } ) + + it('should re-throw error occurred by fallback', async () => { + render( + <>This is expected}> + ( + + ErrorBoundary's fallback before error + + )} + > + + ErrorBoundary's children before error + + + + ) + + expect(screen.queryByText("ErrorBoundary's children before error")).toBeInTheDocument() + await waitFor(() => expect(screen.queryByText("ErrorBoundary's fallback before error")).toBeInTheDocument()) + await waitFor(() => expect(screen.queryByText('This is expected')).toBeInTheDocument()) + }) }) describe('', () => { diff --git a/packages/react/src/ErrorBoundary.tsx b/packages/react/src/ErrorBoundary.tsx index f2c7d9bb1..d8cd59798 100644 --- a/packages/react/src/ErrorBoundary.tsx +++ b/packages/react/src/ErrorBoundary.tsx @@ -115,6 +115,9 @@ class BaseErrorBoundary extends Component - } else { - childrenOrFallback = fallback - } + const Fallback = fallback + childrenOrFallback = ( + + {typeof Fallback === 'function' ? : Fallback} + + ) } return ( @@ -163,6 +166,25 @@ class BaseErrorBoundary extends Component { + componentDidCatch(fallbackError: Error) { + if (fallbackError instanceof SuspensiveError) { + throw fallbackError + } + throw new InternalFallbackError(fallbackError) + } + render() { + return this.props.children + } +} + /** * This component provides a simple and reusable wrapper that you can use to wrap around your components. Any rendering errors in your components hierarchy can then be gracefully handled. * @see {@link https://suspensive.org/docs/react/ErrorBoundary Suspensive Docs} From 2c74e225192025b47f020e96c33cfdf3dc0b9699 Mon Sep 17 00:00:00 2001 From: Jonghyeon Ko Date: Mon, 6 Jan 2025 23:11:19 +0900 Subject: [PATCH 2/9] Create pretty-brooms-float.md --- .changeset/pretty-brooms-float.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/pretty-brooms-float.md diff --git a/.changeset/pretty-brooms-float.md b/.changeset/pretty-brooms-float.md new file mode 100644 index 000000000..ab3ae71b9 --- /dev/null +++ b/.changeset/pretty-brooms-float.md @@ -0,0 +1,5 @@ +--- +"@suspensive/react": minor +--- + +feat(react): prevent recursive expose fallback when fallback throw error From 0bd6b0e6c8dbf54862235546fbbde4e31a3a8035 Mon Sep 17 00:00:00 2001 From: Jonghyeon Ko Date: Tue, 7 Jan 2025 00:28:07 +0900 Subject: [PATCH 3/9] fix(react): update name of internal interface Co-authored-by: Lee HyunJae (whale) <71202076+2-NOW@users.noreply.github.com> --- packages/react/src/ErrorBoundary.tsx | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/packages/react/src/ErrorBoundary.tsx b/packages/react/src/ErrorBoundary.tsx index d8cd59798..e625927dd 100644 --- a/packages/react/src/ErrorBoundary.tsx +++ b/packages/react/src/ErrorBoundary.tsx @@ -115,8 +115,8 @@ class BaseErrorBoundary extends Component + {typeof Fallback === 'function' ? : Fallback} - + ) } @@ -166,19 +166,16 @@ class BaseErrorBoundary extends Component { - componentDidCatch(fallbackError: Error) { - if (fallbackError instanceof SuspensiveError) { - throw fallbackError - } - throw new InternalFallbackError(fallbackError) +class FallbackBoundary extends Component<{ children: ReactNode }> { + componentDidCatch(originalError: Error) { + throw originalError instanceof SuspensiveError ? originalError : new ErrorInFallback(originalError) } render() { return this.props.children From 258e27fefa4730f504248ae454a0a5c12933dd91 Mon Sep 17 00:00:00 2001 From: Jonghyeon Ko Date: Tue, 7 Jan 2025 08:54:11 +0900 Subject: [PATCH 4/9] chore: add co-author Co-authored-by: lucas0530 <23375098+lucas0530@users.noreply.github.com> From bad8c59326123fc50930ab8e72373aa8ad0678d3 Mon Sep 17 00:00:00 2001 From: Jonghyeon Ko Date: Tue, 7 Jan 2025 14:13:51 +0900 Subject: [PATCH 5/9] chore: add co-author Co-authored-by: HYUNGU KANG <69349293+linegu@users.noreply.github.com> From b6ead4e4bbc4ddd713464a28d82658e65d890a2a Mon Sep 17 00:00:00 2001 From: Jonghyeon Ko Date: Thu, 9 Jan 2025 14:01:40 +0900 Subject: [PATCH 6/9] docs(react): add visualization --- examples/visualization/package.json | 1 + examples/visualization/src/app/layout.tsx | 3 + .../ErrorBoundary/ErrorInFallback/page.tsx | 71 +++++++++++++++++++ pnpm-lock.yaml | 62 +++++++--------- 4 files changed, 100 insertions(+), 37 deletions(-) create mode 100644 examples/visualization/src/app/react/ErrorBoundary/ErrorInFallback/page.tsx diff --git a/examples/visualization/package.json b/examples/visualization/package.json index e36ac69e3..e19db182b 100644 --- a/examples/visualization/package.json +++ b/examples/visualization/package.json @@ -22,6 +22,7 @@ "next": "catalog:", "react": "catalog:react19", "react-dom": "catalog:react19", + "react-error-boundary": "^5.0.0", "sharp": "catalog:", "zod": "^3.24.1" }, diff --git a/examples/visualization/src/app/layout.tsx b/examples/visualization/src/app/layout.tsx index 4d891f734..aff09eef5 100644 --- a/examples/visualization/src/app/layout.tsx +++ b/examples/visualization/src/app/layout.tsx @@ -31,6 +31,9 @@ export default function RootLayout({ children }: { children: React.ReactNode })
  • {``} shouldCatch prop
  • +
  • + {``}'s fallback Error +
  • zod: no param
  • diff --git a/examples/visualization/src/app/react/ErrorBoundary/ErrorInFallback/page.tsx b/examples/visualization/src/app/react/ErrorBoundary/ErrorInFallback/page.tsx new file mode 100644 index 000000000..536022c7e --- /dev/null +++ b/examples/visualization/src/app/react/ErrorBoundary/ErrorInFallback/page.tsx @@ -0,0 +1,71 @@ +'use client' + +import { ErrorBoundary as SuspensiveErrorBoundary } from '@suspensive/react' +import { type PropsWithChildren, useCallback, useEffect, useRef, useState } from 'react' +import { ErrorBoundary as ReactErrorBoundary } from 'react-error-boundary' +import { Area } from '~/components/uis' + +export const useTimeout = (fn: () => void, ms: number) => { + const fnRef = useRef(fn) + fnRef.current = fn + const fnPreserved = useCallback(() => fnRef.current(), []) + useEffect(() => { + const id = setTimeout(fnPreserved, ms) + return () => clearTimeout(id) + }, [fnPreserved, ms]) +} + +export const Throw = { + Error: ({ message, after = 0, children }: PropsWithChildren<{ message: string; after?: number }>) => { + const [isNeedThrow, setIsNeedThrow] = useState(after === 0) + if (isNeedThrow) { + throw new Error(message) + } + useTimeout(() => setIsNeedThrow(true), after) + return <>{children} + }, +} + +export default function Page() { + return ( +
    + + <>This is expected}> + { + console.log("@suspensive/react's ErrorBoundary fallback") + return ( + + SuspensiveErrorBoundary's fallback before error + + ) + }} + > + + SuspensiveErrorBoundary's children before error + + + + + + + <>This is expected}> + { + console.log("react-error-boundary's ErrorBoundary fallback") + return ( + + ReactErrorBoundary's fallback before error + + ) + }} + > + + ReactErrorBoundary's children before error + + + + +
    + ) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 342376304..994abb82d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -176,7 +176,7 @@ importers: version: 6.6.3 '@testing-library/react': specifier: ^16.1.0 - version: 16.1.0(@testing-library/dom@10.4.0)(@types/react-dom@19.0.2(@types/react@19.0.1))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 16.1.0(@testing-library/dom@10.4.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@testing-library/user-event': specifier: ^14.5.2 version: 14.5.2(@testing-library/dom@10.4.0) @@ -526,7 +526,7 @@ importers: version: 29.7.0(@types/node@22.10.1)(ts-node@10.9.2(@types/node@22.10.1)(typescript@5.7.2)) jest-expo: specifier: catalog:react19 - version: 52.0.2(@babel/core@7.26.0)(expo@52.0.17(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@expo/metro-runtime@4.0.0(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0)))(graphql@16.9.0)(react-native-webview@13.12.5(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0))(jest@29.7.0(@types/node@22.10.1)(ts-node@10.9.2(@types/node@22.10.1)(typescript@5.7.2)))(react-dom@19.0.0(react@19.0.0))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0)(webpack@5.96.1(esbuild@0.24.0)) + version: 52.0.2(@babel/core@7.26.0)(expo@52.0.17(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@expo/metro-runtime@4.0.0(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0)))(graphql@16.9.0)(react-native-webview@13.12.5(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0))(jest@29.7.0(@types/node@22.10.1))(react-dom@19.0.0(react@19.0.0))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0)(webpack@5.96.1(esbuild@0.24.0)) react-test-renderer: specifier: 19.0.0 version: 19.0.0(react@19.0.0) @@ -566,6 +566,9 @@ importers: react-dom: specifier: catalog:react19 version: 19.0.0(react@19.0.0) + react-error-boundary: + specifier: ^5.0.0 + version: 5.0.0(react@19.0.0) sharp: specifier: 'catalog:' version: 0.33.5 @@ -757,7 +760,7 @@ importers: version: 29.7.0(@types/node@22.10.1)(ts-node@10.9.2(@types/node@22.10.1)(typescript@5.7.2)) jest-expo: specifier: catalog:react19 - version: 52.0.2(@babel/core@7.26.0)(expo@52.0.17(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@expo/metro-runtime@4.0.0(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0)))(graphql@16.9.0)(react-native-webview@13.12.5(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0))(jest@29.7.0(@types/node@22.10.1)(ts-node@10.9.2(@types/node@22.10.1)(typescript@5.7.2)))(react-dom@19.0.0(react@19.0.0))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0)(webpack@5.96.1(esbuild@0.24.0)) + version: 52.0.2(@babel/core@7.26.0)(expo@52.0.17(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@expo/metro-runtime@4.0.0(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0)))(graphql@16.9.0)(react-native-webview@13.12.5(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0))(jest@29.7.0(@types/node@22.10.1))(react-dom@19.0.0(react@19.0.0))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0)(webpack@5.96.1(esbuild@0.24.0)) react: specifier: catalog:react19 version: 19.0.0 @@ -2409,7 +2412,7 @@ packages: '@expo/bunyan@4.0.1': resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==} - engines: {'0': node >=0.10.0} + engines: {node: '>=0.10.0'} '@expo/cli@0.22.3': resolution: {integrity: sha512-1HBtqInFDFHUJWzTJ1CJj5MR3JwvOiozmRUWF2kVQAeq/bKzSYM6We6B3XoZBM5XP6z6WtnrG87C7BjeW5E/cA==} @@ -3516,8 +3519,8 @@ packages: engines: {node: '>=18'} peerDependencies: '@testing-library/dom': ^10.0.0 - '@types/react': ^18.0.0 || ^19.0.0 - '@types/react-dom': ^18.0.0 || ^19.0.0 + '@types/react': npm:types-react@rc + '@types/react-dom': npm:types-react-dom@rc react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 peerDependenciesMeta: @@ -3781,7 +3784,7 @@ packages: '@types/react-dom@19.0.2': resolution: {integrity: sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg==} peerDependencies: - '@types/react': ^19.0.0 + '@types/react': ^19.0.1 '@types/react-test-renderer@19.0.0': resolution: {integrity: sha512-qDVnNybqFm2eZKJ4jD34EvRd6VHD67KjgnWaEMM0Id9L22EpWe3nOSVKHWL1XWRCxUWe3lhXwlEeCKD1BlJCQA==} @@ -8999,6 +9002,11 @@ packages: peerDependencies: react: ^19.0.0 + react-error-boundary@5.0.0: + resolution: {integrity: sha512-tnjAxG+IkpLephNcePNA7v6F/QpWLH8He65+DmedchDwg162JZqx4NmbXj0mlAYVVEd81OW7aFhmbsScYfiAFQ==} + peerDependencies: + react: '>=16.13.1' + react-fast-compare@3.2.2: resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} @@ -14584,15 +14592,12 @@ snapshots: optionalDependencies: jest: 29.7.0(@types/node@22.10.1)(ts-node@10.9.2(@types/node@22.10.1)(typescript@5.7.2)) - '@testing-library/react@16.1.0(@testing-library/dom@10.4.0)(@types/react-dom@19.0.2(@types/react@19.0.1))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@testing-library/react@16.1.0(@testing-library/dom@10.4.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@babel/runtime': 7.26.0 '@testing-library/dom': 10.4.0 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.1 - '@types/react-dom': 19.0.2(@types/react@19.0.1) '@testing-library/user-event@14.5.2(@testing-library/dom@10.4.0)': dependencies: @@ -15043,28 +15048,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/browser@2.1.8(@types/node@22.10.1)(playwright@1.49.0)(typescript@5.7.2)(vite@5.4.11(@types/node@22.10.1)(lightningcss@1.28.1)(terser@5.36.0))(vitest@2.1.8)': - dependencies: - '@testing-library/dom': 10.4.0 - '@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0) - '@vitest/mocker': 2.1.8(msw@2.6.4(@types/node@22.10.1)(typescript@5.7.2))(vite@5.4.11(@types/node@22.10.1)(lightningcss@1.28.1)(terser@5.36.0)) - '@vitest/utils': 2.1.8 - magic-string: 0.30.12 - msw: 2.6.4(@types/node@22.10.1)(typescript@5.7.2) - sirv: 3.0.0 - tinyrainbow: 1.2.0 - vitest: 2.1.8(@types/node@22.10.1)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(lightningcss@1.28.1)(msw@2.6.4(@types/node@22.10.1)(typescript@5.7.2))(terser@5.36.0) - ws: 8.18.0 - optionalDependencies: - playwright: 1.49.0 - transitivePeerDependencies: - - '@types/node' - - bufferutil - - typescript - - utf-8-validate - - vite - optional: true - '@vitest/browser@2.1.8(@types/node@22.10.1)(playwright@1.49.0)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.1)(jiti@2.4.0)(lightningcss@1.28.1)(terser@5.36.0)(yaml@2.6.1))(vitest@2.1.8)': dependencies: '@testing-library/dom': 10.4.0 @@ -18875,7 +18858,7 @@ snapshots: jest-mock: 29.7.0 jest-util: 29.7.0 - jest-expo@52.0.2(@babel/core@7.26.0)(expo@52.0.17(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@expo/metro-runtime@4.0.0(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0)))(graphql@16.9.0)(react-native-webview@13.12.5(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0))(jest@29.7.0(@types/node@22.10.1)(ts-node@10.9.2(@types/node@22.10.1)(typescript@5.7.2)))(react-dom@19.0.0(react@19.0.0))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0)(webpack@5.96.1(esbuild@0.24.0)): + jest-expo@52.0.2(@babel/core@7.26.0)(expo@52.0.17(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@expo/metro-runtime@4.0.0(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0)))(graphql@16.9.0)(react-native-webview@13.12.5(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0))(jest@29.7.0(@types/node@22.10.1))(react-dom@19.0.0(react@19.0.0))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0))(react@19.0.0)(webpack@5.96.1(esbuild@0.24.0)): dependencies: '@expo/config': 10.0.6 '@expo/json-file': 9.0.0 @@ -18888,7 +18871,7 @@ snapshots: jest-environment-jsdom: 29.7.0 jest-snapshot: 29.7.0 jest-watch-select-projects: 2.0.0 - jest-watch-typeahead: 2.2.1(jest@29.7.0(@types/node@22.10.1)(ts-node@10.9.2(@types/node@22.10.1)(typescript@5.7.2))) + jest-watch-typeahead: 2.2.1(jest@29.7.0(@types/node@22.10.1)) json5: 2.2.3 lodash: 4.17.21 react-native: 0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@19.0.1)(react@19.0.0) @@ -19083,7 +19066,7 @@ snapshots: chalk: 3.0.0 prompts: 2.4.2 - jest-watch-typeahead@2.2.1(jest@29.7.0(@types/node@22.10.1)(ts-node@10.9.2(@types/node@22.10.1)(typescript@5.7.2))): + jest-watch-typeahead@2.2.1(jest@29.7.0(@types/node@22.10.1)): dependencies: ansi-escapes: 6.2.1 chalk: 4.1.2 @@ -21318,6 +21301,11 @@ snapshots: react: 19.0.0 scheduler: 0.25.0 + react-error-boundary@5.0.0(react@19.0.0): + dependencies: + '@babel/runtime': 7.26.0 + react: 19.0.0 + react-fast-compare@3.2.2: {} react-freeze@1.0.4(react@19.0.0): @@ -23340,7 +23328,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.10.1 - '@vitest/browser': 2.1.8(@types/node@22.10.1)(playwright@1.49.0)(typescript@5.7.2)(vite@5.4.11(@types/node@22.10.1)(lightningcss@1.28.1)(terser@5.36.0))(vitest@2.1.8) + '@vitest/browser': 2.1.8(@types/node@22.10.1)(playwright@1.49.0)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.1)(jiti@2.4.0)(lightningcss@1.28.1)(terser@5.36.0)(yaml@2.6.1))(vitest@2.1.8) '@vitest/ui': 2.1.8(vitest@2.1.8) jsdom: 25.0.1 transitivePeerDependencies: From be9e8795dd0041590ee55b0c386de502c336f4d2 Mon Sep 17 00:00:00 2001 From: Jonghyeon Ko Date: Thu, 9 Jan 2025 16:15:55 +0900 Subject: [PATCH 7/9] chore: add case to compare with react-error-boundary --- packages/react/package.json | 3 ++- packages/react/src/ErrorBoundary.spec.tsx | 29 ++++++++++++++++++++++- pnpm-lock.yaml | 3 +++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/packages/react/package.json b/packages/react/package.json index d1c4105b9..06e222332 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -53,7 +53,8 @@ "@suspensive/tsconfig": "workspace:*", "@suspensive/tsup": "workspace:*", "@types/react": "catalog:react19", - "react": "catalog:react19" + "react": "catalog:react19", + "react-error-boundary": "^5.0.0" }, "peerDependencies": { "react": "^18 || ^19" diff --git a/packages/react/src/ErrorBoundary.spec.tsx b/packages/react/src/ErrorBoundary.spec.tsx index 8132526d2..1a8d08427 100644 --- a/packages/react/src/ErrorBoundary.spec.tsx +++ b/packages/react/src/ErrorBoundary.spec.tsx @@ -2,6 +2,7 @@ import { act, render, screen, waitFor } from '@testing-library/react' import { userEvent } from '@testing-library/user-event' import ms from 'ms' import { type ComponentRef, createElement, createRef } from 'react' +import { ErrorBoundary as ReactErrorBoundary } from 'react-error-boundary' import { ErrorBoundary, type ErrorBoundaryFallbackProps, @@ -294,7 +295,7 @@ describe('', () => { } ) - it('should re-throw error occurred by fallback', async () => { + it('should re-throw error in fallback', async () => { render( <>This is expected}> ', () => { await waitFor(() => expect(screen.queryByText("ErrorBoundary's fallback before error")).toBeInTheDocument()) await waitFor(() => expect(screen.queryByText('This is expected')).toBeInTheDocument()) }) + it('should not re-throw error in fallback (react-error-boundary)', async () => { + render( + <>This is expected}> + ( + + ErrorBoundary(react-error-boundary)'s fallback before error + + )} + > + + ErrorBoundary(react-error-boundary)'s children before error + + + + ) + + expect(screen.queryByText("ErrorBoundary(react-error-boundary)'s children before error")).toBeInTheDocument() + await waitFor(() => + expect(screen.queryByText("ErrorBoundary(react-error-boundary)'s fallback before error")).toBeInTheDocument() + ) + await waitFor(() => expect(screen.queryByText('This is expected')).not.toBeInTheDocument()) + await waitFor(() => + expect(screen.queryByText("ErrorBoundary(react-error-boundary)'s fallback before error")).toBeInTheDocument() + ) + }) }) describe('', () => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 994abb82d..5e7e15441 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -707,6 +707,9 @@ importers: react: specifier: catalog:react19 version: 19.0.0 + react-error-boundary: + specifier: ^5.0.0 + version: 5.0.0(react@19.0.0) packages/react-dom: devDependencies: From 87014d3ae700ecb5456bb3360ee4daea13404831 Mon Sep 17 00:00:00 2001 From: Jonghyeon Ko Date: Tue, 14 Jan 2025 15:11:29 +0900 Subject: [PATCH 8/9] chore: update --- packages/react/src/ErrorBoundary.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react/src/ErrorBoundary.tsx b/packages/react/src/ErrorBoundary.tsx index 65e449e36..ad775ee71 100644 --- a/packages/react/src/ErrorBoundary.tsx +++ b/packages/react/src/ErrorBoundary.tsx @@ -115,9 +115,6 @@ class BaseErrorBoundary extends Component checkErrorBoundary(shouldCatch, error)) : checkErrorBoundary(shouldCatch, error) From 7c872cc06c0e22ad71675aa40878a18025b92e75 Mon Sep 17 00:00:00 2001 From: Jonghyeon Ko Date: Mon, 20 Jan 2025 18:10:14 +0900 Subject: [PATCH 9/9] chore(react): add co-author https://github.com/bvaughn/react-error-boundary/issues/215\#issuecomment-2589055133 Co-authored-by: Brian Vaughn <29597+bvaughn@users.noreply.github.com>