Skip to Content
👀 Check out the changes in Suspensive v3. read more
Documentation@suspensive/reactMigration guideMigrate to v3

Migrating to v3

What’s new

Now thrown error in ErrorBoundary fallback will be passed to parent #1409 

It is not the developer’s intention to expose fallbacks recursively due to fallback errors, in v3, errors thrown from fallbacks are caught by the parent ErrorBoundary. So this is a new mental model and a BREAKING CHANGE, please understand and use the new behavior.

💡

Errors thrown from the fallback of AS-IS v2 ErrorBoundary cannot be handled by the parent ErrorBoundary, so they are caught by themselves and fallbacks are exposed recursively.

This is also the case in react-error-boundary  where fallbacks are exposed recursively as follows.

  1. children is exposed
  2. fallback is exposed
  3. fallback is exposed
  4. fallback is exposed
  5. … recursively exposed fallback is exposed

Now, errors thrown from the fallback of ErrorBoundary are caught by the parent ErrorBoundary. Therefore, the behavior is as follows.

  1. children are exposed
  2. fallback is exposed
  3. This is expected
const Example = () => ( <ErrorBoundary fallback={() => <>This is expected</>}> <ErrorBoundary fallback={() => ( <Throw.Error message={ERROR_MESSAGE} after={100}> fallback is exposed </Throw.Error> )} > <Throw.Error message={ERROR_MESSAGE} after={100}> children is exposed </Throw.Error> </ErrorBoundary> </ErrorBoundary> ) 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}</> }, }

Now Delay’s children render prop can use the isDelayed flag. #1312 

The Delay component now allows you to use the isDelayed flag in the render prop of its children. This flag can be used to check if the delay has ended. When we use Skeleton UI for Suspense’s fallback, it is better to give a delay of about 200ms and make the skeleton fade-in rather than showing it right away. At this time we can use the isDelayed flag to control the opacity of the skeleton. This allows us to reduce layout shifts while improving user experience.

import { Delay } from '@suspensive/react' const Example = () => ( <Suspense fallback={ <Delay ms={200}> {({ isDelayed }) => ( <Skeleton style={{ opacity: isDelayed ? 1 : 0, transition: 'opacity 0.2s ease-in-out', }} /> )} </Delay> } > <SuspendingComponent /> </Suspense> )

Handling BREAKING CHANGES

Remove wrap & Add with #1452 

wrap has been removed in v3. We added a with method to each component that can replace the functionality of wrap.

  1. You don’t need to understand the builder pattern used in wrap.
  2. Since wrap includes all components internally, the build size increases. In v3, you can import and use only the components you need.
+ import { ErrorBoundaryGroup, ErrorBoundary, Suspense } from '@suspensive/react' - import { wrap } from '@suspensive/react' import { useSuspenseQuery } from '@suspensive/react-query' + const Example = ErrorBoundaryGroup.with( + { blockOutside: false }, + ErrorBoundary.with( + { fallback: ({ error }) => <>{error.message}</>, onError: logger.log }, + Suspense.with({ fallback: <>loading...</>, clientOnly: true }, () => { + const query = useSuspenseQuery({ + queryKey: ['key'], + queryFn: () => api.text(), + }) + return <>{query.data.text}</> + }) + ) + ) - const Example = wrap - .ErrorBoundaryGroup({ blockOutside: false }) - .ErrorBoundary({ - fallback: ({ error }) => <>{error.message}</>, - onError: logger.log, - }) - .Suspense({ fallback: <>loading...</>, clientOnly: true }) - .on(() => { - const query = useSuspenseQuery({ - queryKey: ['key'], - queryFn: () => api.text(), - }) - return <>{query.data.text}</> - })
Last updated on