How to Migrate to v2 from v1
Valtio v2 introduces some key changes to align with modern React features (like the use
hook) and to simplify its core behavior. This guide outlines the breaking changes and how to update your code.
Key Changes in v2
- Promise Handling: Valtio v1 handled promises internally, which is now deprecated in favor of React 19's official
use
hook. In v2, you must use theuse
hook to resolve promises from your state within React components. - Impure
proxy()
: In v1,proxy(obj)
returned a deep clone. In v2,proxy(obj)
modifiesobj
in-place (making it impure). Reusing the initial object after passing it toproxy
is now discouraged. useSnapshot()
Behavior: The internal implementation ofuseSnapshot
has been slightly altered to be more compatible withuseMemo
and the upcoming React Compiler. This may lead to extra re-renders in some rare edge cases but is generally more robust.- Modernization: Deprecated features have been removed, React 18+ and TypeScript 4.5+ are now required, and the build target is ES2018.
Migration Steps
1. Update Promise Resolution with use
Hook
Anywhere you were relying on Valtio to automatically resolve promises for rendering, you now need to wrap the promise-containing snapshot property with the use
hook.
Before (v1):
import { proxy, useSnapshot } from 'valtio';
const state = proxy({ data: fetch(...).then(res => res.json()) });
const Component = () => {
const snap = useSnapshot(state);
// Valtio v1 resolved this automatically
return <>{JSON.stringify(snap.data)}</>;
};
After (v2):
import { use } from 'react'; // From React 19 or 'react18-use' shim
import { proxy, useSnapshot } from 'valtio';
const state = proxy({ data: fetch(...).then(res => res.json()) });
const Component = () => {
const snap = useSnapshot(state);
// Explicitly use the `use` hook
return <>{JSON.stringify(use(snap.data))}</>;
};
2. Handle the Impure proxy(obj)
The recommended practice has always been to not reuse the object passed to proxy
. If you follow this practice, no changes are needed.
If you were reusing the initial object, you must now explicitly clone it before passing it to proxy
or assigning it to a state property to maintain the v1 behavior.
Before (v1):
const initialObj = { text: 'hi' };
const state = proxy(initialObj); // `initialObj` was safe to reuse
After (v2):
import { proxy } from 'valtio';
import { deepClone } from 'valtio/utils';
const initialObj = { text: 'hi' };
const state = proxy(deepClone(initialObj)); // Explicitly clone the object
3. Address useLayoutEffect
SSR Warning in React 18
If you use Valtio with Server-Side Rendering (SSR) in React 18, you may see warnings about useLayoutEffect
. To prevent this, you can conditionally use the vanilla snapshot
function on the server.
import { snapshot, useSnapshot as useSnapshotOrig } from 'valtio';
const isSSR = typeof window === 'undefined';
export const useSnapshot = isSSR ? (p) => snapshot(p) : useSnapshotOrig;
// Then, use this custom `useSnapshot` hook throughout your app.