Migrating to v2
What’s new
New wrap
builder #270
A new feature that wraps a component in <Suspense/>
, <ErrorBoundary/>
, and <ErrorBoundaryGroup/>
all at once.
For <Suspense/>
, <ErrorBoundary/>
, <ErrorBoundaryGroup/>
, etc. many people use hoc to wrap these around a component. This is because these components require some processing on their children. So, in order to not unnecessarily divide components and create depth, we use the hocs for each interface, withErrorBoundary, withErrorBoundaryGroup, and withSuspense, but as we often use each hoc in combination, we also need to improve readability. To improve this, we decided to provide wrap.
import { wrap } from '@suspensive/react'
import { useSuspenseQuery } from '@suspensive/react-query'
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}</>
})
New shouldCatch
prop of <ErrorBoundary/>
#569
Suspensive’s <ErrorBoundary/>
can catch all thrown errors that occur in children. However, because it catches all thrown errors, when using <ErrorBoundary/>
, I thought about placing <ErrorBoundary/>
in a narrower position.
For this reason, we added a new prop called shouldCatch to ErrorBoundary, which allows you to set which Error should be caught.
shouldCatch
: ErrorConstructor
import { ErrorBoundary } from '@suspensive/react'
class CustomError extends Error {}
const Example = () => {
return (
<ErrorBoundary fallback={({ error }) => <>RestError: {error.message}</>}>
<ErrorBoundary
shouldCatch={CustomError}
onError={logOnCustomError}
fallback={({ error }) => <>CustomError: {error.message}</>}
>
<ThrowErrorComponent />
</ErrorBoundary>
</ErrorBoundary>
)
}
shouldCatch
: callback
import { ErrorBoundary } from '@suspensive/react'
class CustomError extends Error {}
const Example = () => {
return (
<ErrorBoundary fallback={({ error }) => <>RestError: {error.message}</>}>
<ErrorBoundary
shouldCatch={(error) => error instanceof CustomError}
onError={logOnCustomError}
fallback={({ error }) => <>CustomError: {error.message}</>}
>
<ThrowErrorComponent />
</ErrorBoundary>
</ErrorBoundary>
)
}
shouldCatch
: boolean
import { ErrorBoundary } from '@suspensive/react'
class CustomError extends Error {}
const Example = () => {
return (
<ErrorBoundary fallback={({ error }) => <>RestError: {error.message}</>}>
<ErrorBoundary
shouldCatch={new Date().toISOString() > '2024-01-01T00:00:00.000Z'}
onError={logOnErrorAfter2024}
fallback={({ error }) => <>ErrorAfter2024: {error.message}</>}
>
<ThrowErrorComponent />
</ErrorBoundary>
</ErrorBoundary>
)
}
New <ErrorBoundary.Consumer/>
, <ErrorBoundaryGroup.Consumer/>
#610
These components can be used to use useErrorBoundary
, useErrorBoundaryGroup
in jsx inlinely.
import { ErrorBoundary, ErrorBoundaryGroup } from '@suspensive/react'
const Example = () => {
return (
<ErrorBoundaryGroup>
<ErrorBoundaryGroup.Consumer>
{({ reset }) => <button onClick={reset}>reset all</button>}
</ErrorBoundaryGroup.Consumer>
<ErrorBoundary fallback={({ error }) => <>{error.message}</>}>
<ErrorBoundary.Consumer>
{({ setError }) => (
<button onClick={() => setError(new Error('error message'))}>
setError
</button>
)}
</ErrorBoundary.Consumer>
</ErrorBoundary>
</ErrorBoundaryGroup>
)
}
Handling BREAKING CHANGES
Removed <AsyncBoundary/>
We removed <AsyncBoundary/>
in v2. #295
Because <AsyncBoundary/>
uses <ErrorBoundary/>
internally, it can be used with useErrorBoundary
and is affected by <ErrorBoundaryGroup/>
. We decided to remove this component from v2, believing that it would be better for maintainability and interface unification for library users.
<AsyncBoundary/>
’s feature is just wrap two component(<Suspense/>
, <Errorboundry/>
) by one.
So, you can split by two like this.
+ import { Suspense, Errorboundry } from '@suspensive/react'
- import { AsyncBoundary } from '@suspensive/react'
+ <Errorboundry fallback={<Error />} onError={onError} onReset={onReset}>
+ <Suspense fallback={<Loading />}>
+ <Children />
+ </Suspense>
+ </Errorboundry>
- <AsyncBoundary pendingFallback={<Loading />} rejectedFallback={<Error />} onError={onError} onReset={onReset}>
- <Children />
- </AsyncBoundary>
Removed withSuspense
, withDelay
, withErrorboundry
, withErrorBoundaryGroup
These all hocs can be replaced beautifully by new hoc builder wrap
in v2.
+ import { wrap } from '@suspensive/react'
- import { withSuspense, withErrorBoundary, withErrorBoundaryGroup } from '@suspensive/react'
+ 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}</>
+ })
- const Example = withErrorBoundaryGroup(
- withErrorBoundary(
- withSuspense(
- () => {
- const query = useSuspenseQuery({
- queryKey: ['key'],
- queryFn: () => api.text(),
- })
- return <>{query.data.text}</>
- },
- { fallback: <>loading...</>, clientOnly: true }
- ),
- { fallback: ({ error }) => <>{error.message}</>, onError: logger.log }
- ),
- { blockOutside: false }
- )
+ import { wrap } from '@suspensive/react'
- import { withSuspense } from '@suspensive/react'
+ const Example = wrap
+ .Suspense({
+ fallback: <>loading...</>,
+ clientOnly: true,
+ })
+ .on(() => {
+ const query = useSuspenseQuery({
+ queryKey: ['key'],
+ queryFn: () => api.text(),
+ })
+ return <>{query.data.text}</>
+ })
- const Example = withSuspense(
- () => {
- const query = useSuspenseQuery({
- queryKey: ['key'],
- queryFn: () => api.text(),
- })
- return <>{query.data.text}</>
- },
- {
- fallback: <>loading...</>,
- clientOnly: true,
- }
- )
Removed <ErrorBoundaryGroup.Reset/>
<ErrorBoundaryGroup.Reset/>
just use useErrorBoundaryGroup
internally. so We thought that changing it to something like Context.Consumer would make the component’s behavior easier to understand for React developers. We changed the name to <ErrorBoundaryGroup.Consumer/>
and kept the interface the same.
import { ErrorBoundaryGroup } from '@suspensive/react'
const Example = () => {
return (
<ErrorBoundaryGroup>
- <ErrorBoundaryGroup.Reset trigger={(group) => <button onClick={group.reset}>reset all</button>} />
+ <ErrorBoundaryGroup.Consumer>
+ {(group) => <button onClick={group.reset}>reset all</button>}
+ </ErrorBoundaryGroup.Consumer>
</ErrorBoundaryGroup>
)
}
Rename defaultOptions
→ defaultProps
of Suspensive
import { ErrorBoundaryGroup } from '@suspensive/react'
const suspensive = new Suspensive({
- defaultOptions: {
+ defaultProps: {
suspense: {
fallback: 'default loading...',
},
},
})
Rename <Suspense.CSROnly/>
→ <Suspense clientOnly/>
as prop
import { Suspense } from '@suspensive/react'
const Example = () => {
return (
- <Suspense.CSROnly fallback={<>loading...</>}>
+ <Suspense clientOnly fallback={<>loading...</>}>
<>children</>
</Suspense.CSROnly>
)
}