feat(island): ✨ add Suspense
component
This commit is contained in:
parent
1abc0d82c4
commit
e0bc4c290f
50
islands/Suspens.tsx
Normal file
50
islands/Suspens.tsx
Normal file
|
@ -0,0 +1,50 @@
|
|||
// import { Suspense } from '@univoq // Error - mismatch in imports version
|
||||
import { JSX } from 'preact'
|
||||
import { useSignal } from '@preact/signals'
|
||||
|
||||
function RenderError(
|
||||
{ error, fallback }: { error: Error; fallback: Fallback | undefined },
|
||||
) {
|
||||
if (fallback) {
|
||||
return fallback({ error })
|
||||
}
|
||||
|
||||
return (
|
||||
<output>
|
||||
<pre>{String(error)}</pre>
|
||||
</output>
|
||||
)
|
||||
}
|
||||
|
||||
type Fallback = ({ error }: { error: Error }) => JSX.Element
|
||||
|
||||
export default function Suspense(
|
||||
{ loader, fallback, signal, children }: {
|
||||
loader: JSX.Element
|
||||
children: Promise<JSX.Element>
|
||||
fallback?: Fallback
|
||||
signal?: AbortSignal
|
||||
},
|
||||
) {
|
||||
const displayed = useSignal(loader)
|
||||
|
||||
signal?.addEventListener('abort', () => {
|
||||
try {
|
||||
signal.throwIfAborted()
|
||||
} catch (error) {
|
||||
displayed.value = RenderError({ error, fallback })
|
||||
}
|
||||
})
|
||||
|
||||
children
|
||||
.then((element) => {
|
||||
if (signal?.aborted) return
|
||||
displayed.value = element
|
||||
})
|
||||
.catch((error) => {
|
||||
if (signal?.aborted) return
|
||||
displayed.value = RenderError({ error, fallback })
|
||||
})
|
||||
|
||||
return <>{displayed}</>
|
||||
}
|
Loading…
Reference in a new issue