inox-tools icon indicating copy to clipboard operation
inox-tools copied to clipboard

request-state not working in .tsx file during SSR?

Open khromov opened this issue 4 months ago • 3 comments

When I try to do the following:

---
// Parent astro component
import { setState } from "@it-astro:state";
setState("publicationLanguage", "en");
---

...
<SomeComponent />

Then in a React component, trying to get the state:

// SomeComponent.tsx
import { getState } from "@it-astro:state";
const language = getState("publicationLanguage");

On SSR of SomeComponent.tsx

Value is undefined (this is unexpected)

On client side hydration

Value is set correctly to "en"

Perhaps I misunderstood the purpose of this library, but I expected the value to be resolvable even during React SSR. Not having this leads to hydration mismatches, Am I doing something wrong?

khromov avatar Aug 12 '25 16:08 khromov

Request State is a lower level thing that was made with the intention of sending data from the server to the client. So this wasn't intended to work. It also wasn't intended to not work, just not something I was considering.

Request Nanostores, which is built on top of Request State, takes the moving data within the server into consideration.

It may introduce racing if you expect data to flow between sibling components. This is not a problem currently because none of the data is available on the server and all of it is available on the client, so there is no inconsistency due to render ordering.

I think enabling this should be fine. That kind of racing problem exist from the consumer behavior, the same would happen by passing down mutable state.

Fryuni avatar Aug 12 '25 20:08 Fryuni

@Fryuni Thank you for your added insight. I tried using @inox-tools/request-nanostores instead and that worked exactly as expected!

khromov avatar Aug 13 '25 10:08 khromov

I tried out this, and the exact example provided doesn't work even when resolving the shared state because it loading the state runs before setting the state.

It is at the top level of a module, that runs when the module is imported.

The frontmatter of an Astro components look like the top-level of a module, but they are not. They are a function. The equivalent place in React would be here:

// Your example shows the code in the component here, that runs once when the module is imported and never again.

export function YourComponent() {
  // Frontmatter of an Astro component would be the code here, it runs once for each time the component is used.
  // If you read the state here after setting it on the parent Astro component it will be available.

  return (
    <p>Your template</p>
  );
}

It works on the client because there the state is present since before the module runs, it was already set by the server before anything got the chance to run.

Fryuni avatar Aug 27 '25 06:08 Fryuni