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() {
	if ($count.get() > 0) $count.set($count.get() - 1)
}
---
import { $count } from '../stores/sharedCounterStore'
---

<div>
	<button id="dec">-</button>
	<span>{$count.get()}</span>
	<button id="inc">+</button>
</div>

<script>
	import { $count, increment, decrement } from '../stores/sharedCounterStore'

	document.getElementById('dec')?.addEventListener('click', decrement)
	document.getElementById('inc')?.addEventListener('click', increment)

	$count.subscribe(value => {
		document.querySelector('span').textContent = value
	})
</script>
<script>
import { $count, increment, decrement } from '../stores/sharedCounterStore'
</script>

<div>
	<button onclick={decrement}>-</button>
	<span>{$count}</span>
	<button onclick={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

Astro Form (Shared State)

Svelte Form

Svelte Form (Shared State)

React Form

React Form (Shared State)

Vue Form

Vue Form (Shared State)

Shared Form Code Examples

import { map } from 'nanostores'

export const $formData = map({ name: '', email: '' })
---
import { $formData } from '../stores/sharedFormStore'
---

<form id="sharedForm">
	<input type="text" id="name" value={$formData.get().name} />
	<input type="email" id="email" value={$formData.get().email} />
</form>

<script>
	import { $formData } from '../stores/sharedFormStore'

	const form = document.getElementById('sharedForm')
	form?.addEventListener('input', (e) => {
		const target = e.target as HTMLInputElement
		$formData.setKey(target.id, target.value)
	})
</script>
<script>
import { $formData } from '../stores/sharedFormStore'

function handleInput(event) {
	const { name, value } = event.target
	$formData.setKey(name, value)
}
</script>

<form>
	<input type="text" name="name" value={$formData.name} oninput={handleInput} />
	<input type="email" name="email" value={$formData.email} oninput={handleInput} />
</form>
import { useStore } from '@nanostores/react'
import { $formData } from '../stores/sharedFormStore'

export function ReactForm() {
	const formData = useStore($formData)

	return (
		<form>
			<input
				type="text"
				value={formData.name}
				onChange={(e) => $formData.setKey('name', e.target.value)}
			/>
			<input
				type="email"
				value={formData.email}
				onChange={(e) => $formData.setKey('email', e.target.value)}
			/>
		</form>
	)
}
<template>
	<form>
		<input
			type="text"
			:value="formData.name"
			@input="(e) => $formData.setKey('name', e.target.value)"
		/>
		<input
			type="email"
			:value="formData.email"
			@input="(e) => $formData.setKey('email', e.target.value)"
		/>
	</form>
</template>

<script setup>
import { useStore } from '@nanostores/vue'
import { $formData } from '../stores/sharedFormStore'

const formData = useStore($formData)
</script>

I'm persistent

0