Skip to content

← all comparisons

Events + global store subscription

Add to cart button

Each button reads the same nanostore to know how many of this product are already in the cart, and writes to it on click.

Each panel header shows the source size of that component file (raw, gzipped, line count). Source-only — framework runtime (React ~45 KB, Vue ~35 KB, Svelte ~5 KB gzipped) is shared across every island and isn't included in these numbers.

React 362 B gzip · 21 lines
AddToCartButtonReact.tsx
How this works

useStore from @nanostores/react subscribe" class="text-blue-700 underline decoration-blue-200 underline-offset-2 hover:decoration-blue-500">subscribes the component to the store and re-renders on every change. Calling addToCart() outside the component just mutates the atom; the subscription propagates the new value back in.

import { useStore } from '@nanostores/react';
import { cart, addToCart } from '../stores/cart';
import type { Product } from '../data/products';

type Props = { product: Product };

export default function AddToCartButtonReact({ product }: Props) {
  const $cart = useStore(cart);
  const qty = $cart[product.id]?.qty ?? 0;

  return (
    <button
      type="button"
      onClick={() => addToCart(product)}
      className="rounded bg-blue-700 px-3 py-1.5 text-sm font-medium text-white hover:bg-blue-800"
    >
      {qty > 0 ? `In cart · ${qty}` : 'Add to cart'}
    </button>
  );
}
Vue 377 B gzip · 22 lines
AddToCartButtonVue.vue
How this works

useStore from @nanostores/vue returns a Vue ref. Use computed() to derive the qty so it stays reactive in templates. Reading $cart.value[id]?.qty inside computed registers the dependency.

<script setup lang="ts">
import { computed } from 'vue';
import { useStore } from '@nanostores/vue';
import { cart, addToCart } from '../stores/cart';
import type { Product } from '../data/products';

const props = defineProps<{ product: Product }>();

const $cart = useStore(cart);
const qty = computed(() => $cart.value[props.product.id]?.qty ?? 0);
</script>

<template>
  <button
    type="button"
    @click="addToCart(props.product)"
    class="rounded bg-blue-700 px-3 py-1.5 text-sm font-medium text-white hover:bg-blue-800"
  >
    {{ qty > 0 ? `In cart · ${qty}` : 'Add to cart' }}
  </button>
</template>
Svelte 314 B gzip · 17 lines
AddToCartButtonSvelte.svelte
How this works

Just import the store and read it as $cart — Svelte's $-prefix auto-subscription works for any object with a Svelte-compatible subscribe" class="text-blue-700 underline decoration-blue-200 underline-offset-2 hover:decoration-blue-500">subscribe() (nanostores conforms). qty is a $derived rune so it recomputes when the store changes.

<script lang="ts">
  import { cart, addToCart } from '../stores/cart';
  import type { Product } from '../data/products';

  let { product }: { product: Product } = $props();

  const qty = $derived($cart[product.id]?.qty ?? 0);
</script>

<button
  type="button"
  onclick={() => addToCart(product)}
  class="rounded bg-blue-700 px-3 py-1.5 text-sm font-medium text-white hover:bg-blue-800"
>
  {qty > 0 ? `In cart · ${qty}` : 'Add to cart'}
</button>