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

Independent Astro Form

Svelte Form

Independent Svelte Form

React Form

Independent React Form

Vue Form

Independent 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

0