Skip to content

Commit 27f340b

Browse files
authored
Fix rendering waterfall of suspended components in a single Suspense boundary (#413)
1 parent 81e7da3 commit 27f340b

File tree

3 files changed

+49
-15
lines changed

3 files changed

+49
-15
lines changed

.changeset/long-ties-brake.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'preact-render-to-string': patch
3+
---
4+
5+
Fix async rendering of multiple suspended components in a single Suspense boundary

src/index.js

+2-15
Original file line numberDiff line numberDiff line change
@@ -542,21 +542,8 @@ function _renderToString(
542542
: result;
543543
} catch (e) {
544544
if (!e || typeof e.then != 'function') throw e;
545-
546-
return e.then(() => {
547-
const result = _renderToString(
548-
rendered,
549-
context,
550-
isSvgMode,
551-
selectValue,
552-
vnode,
553-
asyncMode,
554-
renderer
555-
);
556-
return vnode._suspended
557-
? BEGIN_SUSPENSE_DENOMINATOR + result + END_SUSPENSE_DENOMINATOR
558-
: result;
559-
}, renderNestedChildren);
545+
546+
return e.then(renderNestedChildren);
560547
}
561548
};
562549

test/compat/async.test.jsx

+42
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,48 @@ describe('Async renderToString', () => {
254254
expect(rendered).to.equal(expected);
255255
});
256256

257+
it('should render JSX with multiple suspended direct children within a single suspense boundary that resolve one-after-another', async () => {
258+
const {
259+
Suspender: SuspenderOne,
260+
suspended: suspendedOne
261+
} = createSuspender();
262+
const {
263+
Suspender: SuspenderTwo,
264+
suspended: suspendedTwo
265+
} = createSuspender();
266+
const {
267+
Suspender: SuspenderThree,
268+
suspended: suspendedThree
269+
} = createSuspender();
270+
271+
const promise = renderToStringAsync(
272+
<ul>
273+
<Suspense fallback={null}>
274+
<SuspenderOne>
275+
<li>one</li>
276+
</SuspenderOne>
277+
<SuspenderTwo>
278+
<li>two</li>
279+
</SuspenderTwo>
280+
<SuspenderThree>
281+
<li>three</li>
282+
</SuspenderThree>
283+
</Suspense>
284+
</ul>
285+
);
286+
287+
const expected = `<ul><!--$s--><li>one</li><!--/$s--><!--$s--><li>two</li><!--/$s--><!--$s--><li>three</li><!--/$s--></ul>`;
288+
289+
suspendedOne.promise.then(() => { void suspendedTwo.resolve();});
290+
suspendedTwo.promise.then(() => { void suspendedThree.resolve();});
291+
292+
suspendedOne.resolve();
293+
294+
const rendered = await promise;
295+
296+
expect(rendered).to.equal(expected);
297+
});
298+
257299
it('should rethrow error thrown after suspending', async () => {
258300
const { suspended, getResolved } = createSuspender();
259301

0 commit comments

Comments
 (0)