Vue quick start
@zhuangtai-js/vue fits Vue components that need read-only ComputedRefs, setters, and automatic scope cleanup for ZhuàngTài state.
Requirements and install
Section titled “Requirements and install”@zhuangtai-js/core^0.5.0- Vue >=3.2 <4
pnpm add @zhuangtai-js/core @zhuangtai-js/vue vueMinimal counter
Section titled “Minimal counter”Keep the state model outside the component and call the Vue adapter from setup(). The updater returns a new object and array, preserving Core’s reference equality:
import { atom, computed } from "@zhuangtai-js/core";
export type CounterState = { count: number; history: number[];};
export const counterAtom = atom<CounterState>({ count: 0, history: [] });export const doubleAtom = computed(() => counterAtom.get().count * 2);
export function incrementCounter(state: CounterState): CounterState { const count = state.count + 1; return { ...state, count, history: [...state.history, count] };}<script setup lang="ts">import { useAtom, useAtomValue, useSetAtom } from "@zhuangtai-js/vue";import { counterAtom, doubleAtom, incrementCounter } from "../state/counter";
const [counter, setCounter] = useAtom(counterAtom);const double = useAtomValue(doubleAtom);const reset = useSetAtom(counterAtom);
function increment() { setCounter(incrementCounter);}</script>
<template> <section> <button type="button" @click="increment"> {{ counter.count }} × 2 = {{ double }} </button> <button type="button" @click="reset({ count: 0, history: [] })"> reset ({{ counter.history.length }}) </button> </section></template>Place the state module
Section titled “Place the state module”Put atom, computed, the type, and the updater in src/state/ or src/features/<feature>/state.ts; keep setup() focused on connecting state to the view. Module-level atoms suit client-shared state. For SSR, create user or request state independently for every request instead of reusing a mutable server module-scope reference.
Choose read and write access
Section titled “Choose read and write access”- Read-write:
useAtom(counterAtom)returns[ComputedRef<Value>, setter]; the first value is read-only. - Read-only:
useAtomValue(doubleAtom)returns a read-onlyComputedRefthat templates can use directly. - Setter-only:
useSetAtom(counterAtom)returns a setter without reading or subscribing to the atom.
Call read APIs inside component setup(), <script setup>, or an active effectScope; setter-only access does not require an active scope.
Lifecycle and SSR boundary
Section titled “Lifecycle and SSR boundary”On the client, read APIs register the Core watcher with the current Vue effect scope and clean it up when the scope stops or the component unmounts. Core still owns immediate set, synchronous watch, Object.is equality, and reference-based object updates; Vue’s scheduler still controls DOM commits.
In createSSRApp component setup(), the Vue SSR path only reads an atom.get() snapshot and creates a read-only ComputedRef; it does not install a Core subscription. If the application creates an effectScope() outside a component, it must call scope.stop() at the end of the request and create independent state per request.
Persistence
Section titled “Persistence”When state must survive a reload, see the Persist reference and compose @zhuangtai-js/persist in the state creator. Keep storage, hydration, and request isolation in the state module; components only choose their read/write API.
API reference
Section titled “API reference”useAtomValue: returns a read-onlyComputedRef.useSetAtom: returns a setter that does not subscribe to the value.useAtom: combines the read-onlyComputedRefand setter.
See the Vue reference for complete effect-scope, SSR, and reference semantics.
Next steps
Section titled “Next steps”- Core Concepts: learn synchronous
get,set,watch, andcomputed. - Framework adapter chooser: compare native lifecycles across adapters.
- Persist reference: configure storage, hydration, and lifecycle controls.