Integrations and Compatibility
@zhuangtai-js/core is independent of UI frameworks. Plain JavaScript, SDKs, server modules, and shared data layers can use Core directly. Add an adapter only at a UI boundary that needs native subscriptions and automatic cleanup.
Framework quick starts
Section titled “Framework quick starts”Choose a copy-ready path for the task first, then use the compatibility matrix as version-range evidence:
- React Quick Start
- Preact Quick Start
- Vue Quick Start
- Svelte Quick Start
- Solid Quick Start
- React Native / Expo Quick Start (Expo uses
@zhuangtai-js/react)
Environments and recommended entrypoints
Section titled “Environments and recommended entrypoints”| Environment | Recommended entrypoint | Notes |
|---|---|---|
| Vanilla ESM / Node.js ESM | @zhuangtai-js/core |
Use atom, computed, get, set, and watch directly |
| React | @zhuangtai-js/react |
useAtomValue, useSetAtom, useAtom, and bound hooks |
| React Native / Expo | @zhuangtai-js/react |
Use the React adapter; the app supplies its own storage |
| Preact | @zhuangtai-js/preact |
Preact hooks and useSyncExternalStore from preact/compat |
| Svelte | @zhuangtai-js/svelte |
Standard svelte/store objects from toReadable and toWritable |
| Vue | @zhuangtai-js/vue |
Read-only ComputedRef values, setters, and effect-scope cleanup |
| Solid | @zhuangtai-js/solid |
Accessor values, setters, client owner cleanup, and SSR snapshots |
| CommonJS projects | Import through ESM | Published packages are ESM-only; use import |
Read Framework Adapter Best Practices for complete lifecycle and SSR guidance.
Current compatibility matrix
Section titled “Current compatibility matrix”These release lines and peer ranges match the package manifests. Use them as secondary evidence after choosing a quick start. A 0.x package does not automatically accept an undeclared future Core minor or framework major.
| Package release line | @zhuangtai-js/core |
Other peers |
|---|---|---|
@zhuangtai-js/freeze@0.2.x |
^0.5.0 |
— |
@zhuangtai-js/immer@0.2.x |
^0.5.0 |
— (Immer is a regular dependency) |
@zhuangtai-js/persist@0.5.x |
^0.5.0 |
— |
@zhuangtai-js/preact@0.1.x |
^0.5.0 |
Preact >=10.9 <11 |
@zhuangtai-js/react@0.2.x |
^0.5.0 |
React >=18 <20 |
@zhuangtai-js/solid@0.1.x |
^0.5.0 |
Solid >=1.5 <2 |
@zhuangtai-js/svelte@0.1.x |
^0.5.0 |
Svelte >=4.2 <6 |
@zhuangtai-js/sync@0.2.x |
^0.5.0 |
— |
@zhuangtai-js/vue@0.1.x |
^0.5.0 |
Vue >=3.2 <4 |
The current Core release line is @zhuangtai-js/core@0.5.x. Plugin and adapter versions are independent and do not need to share one version number.
SSR and request isolation
Section titled “SSR and request isolation”Every server-rendered environment must decide which lifecycle owns each atom:
- Create mutable request-specific or user-specific atoms per request instead of sharing server module instances.
- Use client hydration state that matches the server output.
- Preact SSR reads a snapshot without creating a Core subscription.
- The Svelte adapter uses the standard store contract; isolation depends on where the underlying atom is created.
- Vue SSR
renderToStringonly reads anatom.get()snapshot and does not install a Core watcher; only read APIs in an active client effect scope subscribe, and scope cleanup releases them. - Standard Solid SSR reads only a snapshot through the public
isServersignal, requires no owner, and creates no Core watcher. Client subscriptions bind to an owner, and manually created client roots must be explicitly disposed. @zhuangtai-js/persistreads browserlocalStorageby default and also accepts custom storage methods that returnPromiseLikevalues. Server code should pass explicit storage or create the persisted atom only on the client.
Subscription cleanup and state isolation are separate concerns. Automatically stopping a watcher does not prevent a module-level atom from sharing values across requests.
Core and adapter boundaries
Section titled “Core and adapter boundaries”Keep the state model in a framework-independent module and wrap it with different adapters at different UI boundaries. Core Object.is, synchronous watch, and reference semantics do not change across frameworks; objects and arrays still require immutable updates.
When code does not need a template, component rendering, or framework-owned cleanup, use Core directly instead of adding a reactive wrapper.