Skip to content

Commit

Permalink
fixing nested Suspense boundaries
Browse files Browse the repository at this point in the history
  • Loading branch information
dios-david committed Feb 19, 2024
1 parent ad7b662 commit b6aa2ff
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 5 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 13 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export function renderToString(vnode, context) {
* @param {Object} [context={}] Initial root context object
* @returns {string} serialized HTML
*/
export function renderToStringAsync(vnode, context) {
export async function renderToStringAsync(vnode, context) {
// Performance optimization: `renderToString` is synchronous and we
// therefore don't execute any effects. To do that we pass an empty
// array to `options._commit` (`__c`). But we can go one step further
Expand Down Expand Up @@ -113,7 +113,18 @@ export function renderToStringAsync(vnode, context) {
);

if (Array.isArray(rendered)) {
return Promise.all(rendered).then((rendered) => rendered.join(''));
let count = 0;
let resolved = rendered;

// Resolving nested Promises with a maximum depth of 25
while (
resolved.some((element) => typeof element.then === 'function') &&
count++ < 25
) {
resolved = (await Promise.all(resolved)).flat();
}

return resolved.join('');
}

return rendered;
Expand Down
38 changes: 37 additions & 1 deletion test/compat/async.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('Async renderToString', () => {
expect(rendered).to.equal(expected);
});

it('should render JSX with nested suspense boundary', async () => {
it('should render JSX with nested suspended components', async () => {
const {
Suspender: SuspenderOne,
suspended: suspendedOne
Expand Down Expand Up @@ -58,4 +58,40 @@ describe('Async renderToString', () => {

expect(rendered).to.equal(expected);
});

it('should render JSX with nested suspense boundaries', async () => {
const {
Suspender: SuspenderOne,
suspended: suspendedOne
} = createSuspender();
const {
Suspender: SuspenderTwo,
suspended: suspendedTwo
} = createSuspender();

const promise = renderToStringAsync(
<ul>
<Suspense fallback={null}>
<SuspenderOne>
<li>one</li>
<Suspense fallback={null}>
<SuspenderTwo>
<li>two</li>
</SuspenderTwo>
</Suspense>
<li>three</li>
</SuspenderOne>
</Suspense>
</ul>
);

const expected = `<ul><li>one</li><li>two</li><li>three</li></ul>`;

suspendedOne.resolve();
suspendedTwo.resolve();

const rendered = await promise;

expect(rendered).to.equal(expected);
});
});

0 comments on commit b6aa2ff

Please sign in to comment.