Skip to content

Suspense inside a Fragment may scramble the DOM order #2106

@jviide

Description

@jviide

A certain tree of <Suspense> components, some of which are inside <Fragment>, getting resolved in a particular order can cause the DOM order to become scrambled.

Here is a test reproducing the issue (using the helpers from the suspense.test.js file):

	it('should correctly render Suspense components inside Fragments', async () => {
		const [Lazy1, resolve1] = createLazy();
		const [Lazy2, resolve2] = createLazy();
		const [Lazy3, resolve3] = createLazy();

		const Loading = () => <div>Suspended...</div>;
		const loadingHtml = `<div>Suspended...</div>`;

		render(
			<Fragment>
				<Suspense fallback={<Loading />}>
					<Lazy1 />
				</Suspense>
				<Fragment>
					<Suspense fallback={<Loading />}>
						<Lazy2 />
					</Suspense>
				</Fragment>
				<Suspense fallback={<Loading />}>
					<Lazy3 />
				</Suspense>
			</Fragment>,
			scratch
		);

		rerender();
		expect(scratch.innerHTML).to.eql(
			`${loadingHtml}${loadingHtml}${loadingHtml}`
		);

		await resolve2(() => <span>2</span>);
		await resolve1(() => <span>1</span>);
		rerender();
		expect(scratch.innerHTML).to.eql(
			`<span>1</span><span>2</span>${loadingHtml}`
		);

		await resolve3(() => <span>3</span>);
		rerender();
		expect(scratch.innerHTML).to.eql(
			`<span>1</span><span>2</span><span>3</span>`
		);
	});

The second assertion fails, because the HTML output is <span>2</span><div>Suspended...</div><span>1</span>, i.e. the first component's DOM gets bumped to the end of the DOM.

Tested on Preact 10.0.5.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions