Independent State Management
In this section, we explore how to implement independent state management using Nanostores across different frameworks within an Astro project. Independent state means that each component maintains its own isolated state, demonstrating how Nanostores can be used for component-specific state management.
We'll showcase this concept using two common UI patterns: counters and forms. Each example is implemented in Astro, Svelte, React, and Vue, allowing you to compare how independent state management works across these frameworks.
Independent State Counters
These counters demonstrate how each framework can maintain its own independent count state using Nanostores. Notice how updating one counter doesn't affect the others.
Astro Counter
Independent Astro Counter
0
Svelte Counter
Independent Svelte Counter
0
React Counter
Independent React Counter
0
Vue Counter
Independent Vue Counter
0
Counter Code Examples
import { atom } from 'nanostores'
export const astroCount = atom(0)
export const svelteCount = atom(0)
export const reactCount = atom(0)
export const vueCount = atom(0)
export function increment(store) {
store.set(store.get() + 1)
}
export function decrement(store) {
store.set(store.get() - 1)
}
---
import { astroCount, increment, decrement } from '../stores/counterStore'
---
<div>
<button onclick={decrement(astroCount)}>-</button>
<span>{astroCount.get()}</span>
<button onclick={increment(astroCount)}>+</button>
</div>
<script>
import { astroCount } from '../stores/counterStore'
astroCount.subscribe(value => {
document.querySelector('span').textContent = value
})
</script>
<script>
import { svelteCount, increment, decrement } from '../stores/counterStore'
</script>
<div>
<button on:click={() => decrement(svelteCount)}>-</button>
<span>{$svelteCount}</span>
<button on:click={() => increment(svelteCount)}>+</button>
</div>
import { useStore } from '@nanostores/react'
import { reactCount, increment, decrement } from '../stores/counterStore'
export function ReactCounter() {
const count = useStore(reactCount)
return (
<div>
<button onClick={() => decrement(reactCount)}>-</button>
<span>{count}</span>
<button onClick={() => increment(reactCount)}>+</button>
</div>
)
}
<template>
<div>
<button @click="decrement(vueCount)">-</button>
<span>{{ count }}</span>
<button @click="increment(vueCount)">+</button>
</div>
</template>
<script setup>
import { useStore } from '@nanostores/vue'
import { vueCount, increment, decrement } from '../stores/counterStore'
const count = useStore(vueCount)
</script>
Independent State Forms
These forms demonstrate how complex state (multiple form fields) can be managed independently for each framework using Nanostores. Each form maintains its own state without affecting the others.
Astro Form
Svelte Form
React Form
Vue Form
Form Code Examples
import { map } from 'nanostores'
export const astroForm = map({ name: '', email: '' })
export const svelteForm = map({ name: '', email: '' })
export const reactForm = map({ name: '', email: '' })
export const vueForm = map({ name: '', email: '' })
export function updateForm(store, field, value) {
store.setKey(field, value)
}
---
import { astroForm, updateForm } from '../stores/formStore'
---
<form>
<input
type="text"
value={astroForm.get().name}
onchange={(e) => updateForm(astroForm, 'name', e.target.value)}
/>
<input
type="email"
value={astroForm.get().email}
onchange={(e) => updateForm(astroForm, 'email', e.target.value)}
/>
</form>
<script>
import { astroForm } from '../stores/formStore'
astroForm.subscribe(value => {
console.log('Form updated:', value)
})
</script>
<script>
import { svelteForm, updateForm } from '../stores/formStore'
</script>
<form>
<input
type="text"
bind:value={$svelteForm.name}
on:input={(e) => updateForm(svelteForm, 'name', e.target.value)}
/>
<input
type="email"
bind:value={$svelteForm.email}
on:input={(e) => updateForm(svelteForm, 'email', e.target.value)}
/>
</form>
import { useStore } from '@nanostores/react'
import { reactForm, updateForm } from '../stores/formStore'
export function ReactForm() {
const form = useStore(reactForm)
return (
<form>
<input
type="text"
value={form.name}
onChange={(e) => updateForm(reactForm, 'name', e.target.value)}
/>
<input
type="email"
value={form.email}
onChange={(e) => updateForm(reactForm, 'email', e.target.value)}
/>
</form>
)
}
<template>
<form>
<input
type="text"
:value="form.name"
@input="(e) => updateForm(vueForm, 'name', e.target.value)"
/>
<input
type="email"
:value="form.email"
@input="(e) => updateForm(vueForm, 'email', e.target.value)"
/>
</form>
</template>
<script setup>
import { useStore } from '@nanostores/vue'
import { vueForm, updateForm } from '../stores/formStore'
const form = useStore(vueForm)
</script>
I'm persistent