Shared State Management
Welcome to the shared state management demonstration! This page showcases how Nanostores can be used to manage shared state across different frameworks within an Astro project. Shared state means that all components, regardless of their framework, can access and modify the same state.
We'll demonstrate this concept using two common UI patterns: counters and forms. Each example is implemented in Astro, Svelte, React, and Vue, all sharing the same state. This allows you to see how changes in one component immediately reflect in all others, regardless of the framework used.
Shared State Counters
These counters demonstrate how a single shared state can be accessed and modified by components built with different frameworks. Notice how updating the count in one counter updates all the others simultaneously.
Astro Counter
Astro Counter (Shared State)
0
Svelte Counter
Svelte Counter (Shared State)
0
React Counter
React Counter (Shared State)
0
Vue Counter
Vue Counter (Shared State)
0
Shared Counter Code Examples
import { atom } from 'nanostores'
export const count = atom(0)
export function increment() {
count.set(count.get() + 1)
}
export function decrement() {
count.set(count.get() - 1)
}
---
import { count, increment, decrement } from '../stores/sharedCounterStore'
---
<div>
<button onclick={decrement}>-</button>
<span>{count.get()}</span>
<button onclick={increment}>+</button>
</div>
<script>
import { count } from '../stores/sharedCounterStore'
count.subscribe(value => {
document.querySelector('span').textContent = value
})
</script>
<script>
import { count, increment, decrement } from '../stores/sharedCounterStore'
</script>
<div>
<button on:click={decrement}>-</button>
<span>{$count}</span>
<button on:click={increment}>+</button>
</div>
import { useStore } from '@nanostores/react'
import { count, increment, decrement } from '../stores/sharedCounterStore'
export function ReactCounter() {
const $count = useStore(count)
return (
<div>
<button onClick={decrement}>-</button>
<span>{$count}</span>
<button onClick={increment}>+</button>
</div>
)
}
<template>
<div>
<button @click="decrement">-</button>
<span>{{ count }}</span>
<button @click="increment">+</button>
</div>
</template>
<script setup>
import { useStore } from '@nanostores/vue'
import { count, increment, decrement } from '../stores/sharedCounterStore'
const count = useStore(count)
</script>
Shared State Forms
These forms demonstrate how complex shared state (multiple form fields) can be managed across different frameworks using Nanostores. Notice how updating a field in one form updates the same field in all other forms instantly.
Astro Form
Svelte Form
React Form
Vue Form
Shared Form Code Examples
import { map } from 'nanostores'
export const formData = map({ name: '', email: '' })
export function updateForm(field, value) {
formData.setKey(field, value)
}
---
import { formData, updateForm } from '../stores/sharedFormStore'
---
<form>
<input
type="text"
value={formData.get().name}
onchange={(e) => updateForm('name', e.target.value)}
/>
<input
type="email"
value={formData.get().email}
onchange={(e) => updateForm('email', e.target.value)}
/>
</form>
<script>
import { formData } from '../stores/sharedFormStore'
formData.subscribe(value => {
console.log('Form updated:', value)
})
</script>
<script>
import { formData, updateForm } from '../stores/sharedFormStore'
</script>
<form>
<input
type="text"
bind:value={$formData.name}
on:input={(e) => updateForm('name', e.target.value)}
/>
<input
type="email"
bind:value={$formData.email}
on:input={(e) => updateForm('email', e.target.value)}
/>
</form>
import { useStore } from '@nanostores/react'
import { formData, updateForm } from '../stores/sharedFormStore'
export function ReactForm() {
const $formData = useStore(formData)
return (
<form>
<input
type="text"
value={$formData.name}
onChange={(e) => updateForm('name', e.target.value)}
/>
<input
type="email"
value={$formData.email}
onChange={(e) => updateForm('email', e.target.value)}
/>
</form>
)
}
<template>
<form>
<input
type="text"
:value="formData.name"
@input="(e) => updateForm('name', e.target.value)"
/>
<input
type="email"
:value="formData.email"
@input="(e) => updateForm('email', e.target.value)"
/>
</form>
</template>
<script setup>
import { useStore } from '@nanostores/vue'
import { formData, updateForm } from '../stores/sharedFormStore'
const formData = useStore(formData)
</script>
I'm persistent