solid icon indicating copy to clipboard operation
solid copied to clipboard

`renderToStringAsync` with `NoHydration` and nested resources + `Suspense` boundaries triggers resource collision

Open fongandrew opened this issue 3 months ago • 1 comments

Describe the bug

Suppose you have the following Post component, which uses a resource to load a user:

async function loadPost(id) {
	await new Promise((resolve) => setTimeout(resolve, 10));
	return {
		id,
		userId: 'alice',
		content: 'Hello world',
	};
}

export function Post(props) {
	const [post] = createResource(
		() => props.id,
		(postId) => loadPost(postId),
	);

	return (
		<div>
			<Suspense>
				<User id={post()?.userId} />
			</Suspense>
			<span>Post: {post()?.content}</span>
		</div>
	);
}

The User component in turn loads data via a resource and renders that:

async function loadUser(id) {
	await new Promise((resolve) => setTimeout(resolve, 10));
	return {
		id,
		name: `User ${id}`,
	};
}

export function User(props) {
	const [user] = createResource(
		() => props.id,
		(id) => loadUser(id),
	);

	return <span>User: {user()?.name}</span>;
}

If you render with renderToStringAsync, this will wait for all the resources / Suspense boundaries to resolve. But if you render this under NoHydrate like so:

await renderToStringAsync(() => (
	<NoHydration>
		<Post id="post123" />
	</NoHydration>
));

This can result in the nested User resource returning the return value from the parent Post resource. So user() returns the same value as post() does.

This only happens with NoHydration. Removing it seems to resolve the issue.

Your Example Website or App

https://github.com/fongandrew/solidjs-resource-repro

Steps to Reproduce the Bug or Issue

  1. Nest components with createResource calls and Suspense boundaries
  2. Render with renderToStringAsync and <NoHydrate>

Expected behavior

I expect the accessor returned by each createResource to always return the value returned by the fetcher it was created with (or undefined if still loading). And I expect it to work with NoHydrate (the use case here is that we're just rendering a pure HTML page that will never be hydrated but still relies on a waterfall of async data loading).

Screenshots or Videos

No response

Platform

  • OS: macOS
  • Browser: Node
  • Version: 23.5.0

Additional context

No response

fongandrew avatar Sep 21 '25 02:09 fongandrew

Similar to this: https://github.com/solidjs/solid/issues/2131

IDs aren't managed under NoHydration which leads to the issue. Different symptoms of the same problem.

ryansolid avatar Sep 22 '25 23:09 ryansolid