docs icon indicating copy to clipboard operation
docs copied to clipboard

Using nanostores in astro components

Open lstephensca opened this issue 10 months ago • 4 comments

📚 Subject area/topic

Nanostores

📋 Page(s) affected (or suggested, for new content)

https://docs.astro.build/en/recipes/sharing-state-islands/ https://docs.astro.build/en/recipes/sharing-state/

📋 Description of content that is out-of-date or incorrect

Currently, the docs pertaining to sharing-state-islands seem to advise against using nanostores in .astro components in the FAQ section. However, the docs for sharing-state demonstrates setting up nanostores for use inside .astro components with setting state/subscribing to changes. ~~There appears to be a contradiction between the two.~~

🖥️ Reproduction in StackBlitz (if reporting incorrect content or code samples)

No response

lstephensca avatar Apr 18 '24 13:04 lstephensca

I think that would benefit from some rewording, but they are not exactly contradicting.

Explaining:

Can I use Nano Stores in .astro files or other server-side components?

Nano Stores can be imported, written to, and read from in server-side components, but we don’t recommend it! This is due to a few restrictions:

  • Writing to a store from a .astro file or non-hydrated component will not affect the value received by client-side components.
  • You cannot pass a Nano Store as a “prop” to client-side components.
  • You cannot subscribe to store changes from a .astro file, since Astro components do not re-render.

That is referring to server-side components, on Astro components that means the frontmatter:

---
// This runs on the server, not recommended
import {flag} from './stores.js';

const flagValue = flag.get();
---

A <script> block in an Astro component is a plain client-side script generated by the Astro component, it is never executed on the server-side even when pre-rendering. Using nanostores there is not a problem.

---
---
<script>
// This runs on the client, perfectly fine
import {flag} from './stores.js';

const flagValue = flag.get();
</script>

Fryuni avatar Apr 18 '24 13:04 Fryuni

Good point! I should have clarified a bit more in my issue regarding the differences between using nanostores in frontmatter and script blocks and not have been in a rush.

lstephensca avatar Apr 18 '24 14:04 lstephensca

Thanks for the conversation here! I wonder if something like this would address the issue?

Existing:

Nano Stores can be imported, written to, and read from in server-side components, but we don’t recommend it! This is due to a few restrictions:

Change to something like...

Nano Stores can be used in <script> tags to share state between .astro components. However, Using Nano Stores in the frontmatter of server-side components is not recommended because of the following restrictions:

Would something like that help? If so, would someone like to make a PR to update with clearer guidance?

sarah11918 avatar May 04 '24 22:05 sarah11918

I think that is a great improvement!

Fryuni avatar May 05 '24 19:05 Fryuni

I think that would benefit from some rewording, but they are not exactly contradicting.

Explaining:

Can I use Nano Stores in .astro files or other server-side components? Nano Stores can be imported, written to, and read from in server-side components, but we don’t recommend it! This is due to a few restrictions:

  • Writing to a store from a .astro file or non-hydrated component will not affect the value received by client-side components.
  • You cannot pass a Nano Store as a “prop” to client-side components.
  • You cannot subscribe to store changes from a .astro file, since Astro components do not re-render.

That is referring to server-side components, on Astro components that means the frontmatter:

---
// This runs on the server, not recommended
import {flag} from './stores.js';

const flagValue = flag.get();
---

A <script> block in an Astro component is a plain client-side script generated by the Astro component, it is never executed on the server-side even when pre-rendering. Using nanostores there is not a problem.

---
---
<script>
// This runs on the client, perfectly fine
import {flag} from './stores.js';

const flagValue = flag.get();
</script>

Why is not recommended the use of the store in server side?

It could be usefull for i18n purposes, isn't it?

JuanDa237 avatar Oct 01 '24 00:10 JuanDa237

Because a nanostore is a shared state that crosses request. Which leads do data races and information leak between concurrent requests. It is not designed for that.

It can be used for that, but not directly. You need to wrap it into something to isolate the contexts.

In the case of Astro, I've made an integration for it: https://inox-tools.fryuni.dev/request-nanostores

Fryuni avatar Oct 01 '24 02:10 Fryuni