diff --git a/.changeset/heavy-sloths-cry.md b/.changeset/heavy-sloths-cry.md
new file mode 100644
index 00000000..1f8c6fa7
--- /dev/null
+++ b/.changeset/heavy-sloths-cry.md
@@ -0,0 +1,5 @@
+---
+'preact-render-to-string': patch
+---
+
+Ensure that in streaming mode throwing a suspension multiple times from the same component works
diff --git a/src/index.js b/src/index.js
index 0d83e3bf..f1bf5b93 100644
--- a/src/index.js
+++ b/src/index.js
@@ -380,11 +380,12 @@ function _renderToString(
try {
rendered = type.call(component, props, cctx);
- } catch (e) {
- if (asyncMode) {
+ } catch (error) {
+ if (asyncMode && error && typeof error.then == 'function') {
vnode._suspended = true;
}
- throw e;
+
+ throw error;
}
}
@@ -508,17 +509,24 @@ function _renderToString(
return str;
} catch (error) {
if (!asyncMode && renderer && renderer.onError) {
- let res = renderer.onError(error, vnode, (child, parent) =>
- _renderToString(
- child,
- context,
- isSvgMode,
- selectValue,
- parent,
- asyncMode,
- renderer
- )
- );
+ const onError = (error) => {
+ return renderer.onError(error, vnode, (child, parent) => {
+ try {
+ return _renderToString(
+ child,
+ context,
+ isSvgMode,
+ selectValue,
+ parent,
+ asyncMode,
+ renderer
+ );
+ } catch (e) {
+ return onError(e);
+ }
+ });
+ };
+ let res = onError(error);
if (res !== undefined) return res;
diff --git a/test/compat/render-chunked.test.jsx b/test/compat/render-chunked.test.jsx
index 51b93160..3f20e517 100644
--- a/test/compat/render-chunked.test.jsx
+++ b/test/compat/render-chunked.test.jsx
@@ -190,4 +190,38 @@ describe('renderToChunks', () => {
''
]);
});
+
+ it('should support a component that suspends multiple times', async () => {
+ const { Suspender, suspended } = createSuspender();
+ const { Suspender: Suspender2, suspended: suspended2 } = createSuspender();
+
+ function MultiSuspender() {
+ return (
+
it works
it works
'), + '