LocalState

Il est encore possible d'utiliser ref pour de l'etat local, mais il faut faire attention à sa valeur initiale.

Ref Counter: 0

Ref Counter: 0

LocalState
<script setup lang="ts">
const counter = ref(0);
// This will lead to hydration error :
// const counter = ref(Math.random());
</script>

<template>
  <div>
    <p>Ref Counter: {{ counter }}</p>
    <UButton @click="counter--">-</UButton>
    <UButton @click="counter++">+</UButton>
  </div>
</template>

Global Store

Pour les variables globales, on utilisera encore Pinia

Global Counter: 0

Global Counter: 0

GlobalStoreComponent
<script setup lang="ts">
const counter = useCounter();
</script>

<template>
  <div>
    <p>Global Counter: {{ counter.count }}</p>
    <UButton @click="counter.decrement">-</UButton>
    <UButton @click="counter.increment">+</UButton>
  </div>
</template>
GlobalStore
export const useCounter = defineStore("counter", {
  state: () => ({
    count: 0,
  }),
  actions: {
    increment() {
      this.count++;
    },
    decrement() {
      this.count--;
    },
  },
});

Client Only

Il est parfois necessaire d'acceder à des fonctions seulement dispo coté client.

Username: unknown

Username
<script setup lang="ts">
const username = useUsername();
</script>

<template>
  <div>
    <p>Username: {{ username }}</p>
    <UInput v-model="username" />
  </div>
</template>
UsernameComposable
export const useUsername = () => {
  const username = ref("unknown");

  // import .meta .client
  if (false) {
    onMounted(() => {
      const stored = localStorage.getItem("username");
      if (stored) {
        username.value = stored;
      }
      watch(username, (value) => {
        localStorage.setItem("username", value);
      });
    });
  }

  return username;
};

Local composable

On peut toujours utiliser les ref dans des composables, mais encore attention aux valeurs intiales

Local Counter Composable: 0

Local Counter Composable: 0

LocalComposableComponentSource
<script setup lang="ts">
const counter = useLocalCounter();
</script>

<template>
  <div>
    <p>Local Counter Composable: {{ counter.count }}</p>
    <UButton @click="counter.decrement">-</UButton>
    <UButton @click="counter.increment">+</UButton>
  </div>
</template>
LocalComposableComposable
export const useLocalCounter = () => {
  const count = ref(0);

  return {
    count,
    increment: () => count.value++,
    decrement: () => count.value--,
  };
};

UseState

UseState est fait pour être resilient aux changements de valeur initiale, et sa valeur est transferée au client lors de l'hydration.
Cependant sa valeur est globale et partagée dans l'app.

UseState Counter: 0

UseState Counter: 0

<script setup lang="ts">
const counter = useState("counter", () => 0);
// This will work because it's made to be calculated only once
// const counter = useState("counter", () => Math.random());
</script>

<template>
  <div>
    <p>UseState Counter: {{ counter }}</p>
    <UButton @click="counter--">-</UButton>
    <UButton @click="counter++">+</UButton>
  </div>
</template>