Skip to content

Commit 80ba7dc

Browse files
authored
Merge pull request #436 from preactjs/stream-multi-throw
Ensure we can suspend from a given component more than once
2 parents 1667556 + 6bce3dd commit 80ba7dc

File tree

3 files changed

+61
-14
lines changed

3 files changed

+61
-14
lines changed

.changeset/heavy-sloths-cry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'preact-render-to-string': patch
3+
---
4+
5+
Ensure that in streaming mode throwing a suspension multiple times from the same component works

src/index.js

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -380,11 +380,12 @@ function _renderToString(
380380

381381
try {
382382
rendered = type.call(component, props, cctx);
383-
} catch (e) {
384-
if (asyncMode) {
383+
} catch (error) {
384+
if (asyncMode && error && typeof error.then == 'function') {
385385
vnode._suspended = true;
386386
}
387-
throw e;
387+
388+
throw error;
388389
}
389390
}
390391

@@ -508,17 +509,24 @@ function _renderToString(
508509
return str;
509510
} catch (error) {
510511
if (!asyncMode && renderer && renderer.onError) {
511-
let res = renderer.onError(error, vnode, (child, parent) =>
512-
_renderToString(
513-
child,
514-
context,
515-
isSvgMode,
516-
selectValue,
517-
parent,
518-
asyncMode,
519-
renderer
520-
)
521-
);
512+
const onError = (error) => {
513+
return renderer.onError(error, vnode, (child, parent) => {
514+
try {
515+
return _renderToString(
516+
child,
517+
context,
518+
isSvgMode,
519+
selectValue,
520+
parent,
521+
asyncMode,
522+
renderer
523+
);
524+
} catch (e) {
525+
return onError(e);
526+
}
527+
});
528+
};
529+
let res = onError(error);
522530

523531
if (res !== undefined) return res;
524532

test/compat/render-chunked.test.jsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,4 +190,38 @@ describe('renderToChunks', () => {
190190
'</div>'
191191
]);
192192
});
193+
194+
it('should support a component that suspends multiple times', async () => {
195+
const { Suspender, suspended } = createSuspender();
196+
const { Suspender: Suspender2, suspended: suspended2 } = createSuspender();
197+
198+
function MultiSuspender() {
199+
return (
200+
<Suspense fallback="loading part 1...">
201+
<Suspender />
202+
<Suspender2 />
203+
</Suspense>
204+
);
205+
}
206+
207+
const result = [];
208+
const promise = renderToChunks(
209+
<div>
210+
<MultiSuspender />
211+
</div>,
212+
{ onWrite: (s) => result.push(s) }
213+
);
214+
215+
suspended.resolve();
216+
suspended2.resolve();
217+
await promise;
218+
219+
expect(result).to.deep.equal([
220+
'<div><!--preact-island:49-->loading part 1...<!--/preact-island:49--></div>',
221+
'<div hidden>',
222+
createInitScript(1),
223+
createSubtree('49', '<p>it works</p><p>it works</p>'),
224+
'</div>'
225+
]);
226+
});
193227
});

0 commit comments

Comments
 (0)