Comparing version 2.0.0-rc.0 to 2.0.0-rc.1
@@ -6,3 +6,3 @@ { | ||
"type": "commonjs", | ||
"version": "2.0.0-rc.0", | ||
"version": "2.0.0-rc.1", | ||
"publishConfig": { | ||
@@ -85,5 +85,2 @@ "tag": "next" | ||
}, | ||
"resolutions": { | ||
"@types/react": "18.2.56" | ||
}, | ||
"peerDependencies": { | ||
@@ -90,0 +87,0 @@ "@types/react": ">=18.0.0", |
@@ -14,6 +14,10 @@ 'use strict'; | ||
}; | ||
const condUseAffectedDebugValue = useAffectedDebugValue; | ||
const targetCache = /* @__PURE__ */ new WeakMap(); | ||
function useSnapshot(proxyObject, options) { | ||
const notifyInSync = options == null ? void 0 : options.sync; | ||
const affected = react.useMemo(() => /* @__PURE__ */ new WeakMap(), [proxyObject]); | ||
const affected = react.useMemo( | ||
() => proxyObject && /* @__PURE__ */ new WeakMap(), | ||
[proxyObject] | ||
); | ||
const lastSnapshot = react.useRef(); | ||
@@ -52,3 +56,3 @@ let inRender = true; | ||
if (process.env.NODE_ENV !== "production") { | ||
useAffectedDebugValue(currSnapshot, affected); | ||
condUseAffectedDebugValue(currSnapshot, affected); | ||
} | ||
@@ -55,0 +59,0 @@ const proxyCache = react.useMemo(() => /* @__PURE__ */ new WeakMap(), []); |
@@ -166,5 +166,8 @@ <img src="logo.svg" alt="valtio"> | ||
Valtio supports React-suspense and will throw promises that you access within a components render function. This eliminates all the async back-and-forth, you can access your data directly while the parent is responsible for fallback state and error handling. | ||
Valtio is compatible with React 19 `use` hook. This eliminates all the async back-and-forth, you can access your data directly while the parent is responsible for fallback state and error handling. | ||
```jsx | ||
import { use } from 'react' // React 19 | ||
// import { use } from 'react18-use' // React 18 | ||
const state = proxy({ post: fetch(url).then((res) => res.json()) }) | ||
@@ -174,3 +177,3 @@ | ||
const snap = useSnapshot(state) | ||
return <div>{snap.post.title}</div> | ||
return <div>{use(snap.post).title}</div> | ||
} | ||
@@ -187,2 +190,4 @@ | ||
It still suffers from "de-opt", which prevents `useTransition` to work well. To mitigate it, there is a third-party library [use-valtio](https://github.com/valtiojs/use-valtio). | ||
#### Holding objects in state without tracking them | ||
@@ -385,7 +390,7 @@ | ||
Valtio is unopinionated about best practices. | ||
The community is working on recipes on wiki pages. | ||
The community is working on recipes. | ||
- [How to organize actions](https://github.com/pmndrs/valtio/wiki/How-to-organize-actions) | ||
- [How to persist states](https://github.com/pmndrs/valtio/wiki/How-to-persist-states) | ||
- [How to use with context](https://github.com/pmndrs/valtio/wiki/How-to-use-with-context) | ||
- [How to split and compose states](https://github.com/pmndrs/valtio/wiki/How-to-split-and-compose-states) | ||
- [How to organize actions](https://github.com/pmndrs/valtio/blob/main/docs/how-tos/how-to-organize-actions.mdx) | ||
- [How to persist states](https://github.com/pmndrs/valtio/blob/main/docs/how-tos/how-to-persist-states.mdx) | ||
- [How to use with context](https://github.com/pmndrs/valtio/blob/main/docs/how-tos/how-to-use-with-context.mdx) | ||
- [How to split and compose states](https://github.com/pmndrs/valtio/blob/main/docs/how-tos/how-to-split-and-compose-states.mdx) |
@@ -12,3 +12,2 @@ type AnyFunction = (...args: any[]) => any; | ||
} : T; | ||
type CreateSnapshot = <T extends object>(target: T, version: number) => T; | ||
type RemoveListener = () => void; | ||
@@ -19,5 +18,9 @@ type AddListener = (listener: Listener) => RemoveListener; | ||
ensureVersion: (nextCheckVersion?: number) => number, | ||
createSnapshot: CreateSnapshot, | ||
addListener: AddListener | ||
]; | ||
declare let objectIs: (value1: any, value2: any) => boolean; | ||
declare let newProxy: <T extends object>(target: T, handler: ProxyHandler<T>) => T; | ||
declare let canProxy: (x: unknown) => boolean; | ||
declare let createSnapshot: <T extends object>(target: T, version: number) => T; | ||
declare let createHandler: <T extends object>(isInitializing: () => boolean, addPropListener: (prop: string | symbol, propValue: unknown) => void, removePropListener: (prop: string | symbol) => void, notifyUpdate: (op: Op) => void) => ProxyHandler<T>; | ||
export declare function proxy<T extends object>(baseObject?: T): T; | ||
@@ -30,3 +33,14 @@ export declare function getVersion(proxyObject: unknown): number | undefined; | ||
}; | ||
export declare const unstable_buildProxyFunction: (objectIs?: (value1: any, value2: any) => boolean, newProxy?: <T extends object>(target: T, handler: ProxyHandler<T>) => T, canProxy?: (x: unknown) => boolean, snapCache?: WeakMap<object, [version: number, snap: unknown]>, createSnapshot?: CreateSnapshot, proxyCache?: WeakMap<object, object>, versionHolder?: [number, number], proxyFunction?: <T_1 extends object>(baseObject: T_1) => T_1) => readonly [<T_1 extends object>(baseObject: T_1) => T_1, WeakMap<object, ProxyState>, WeakSet<WeakKey>, (value1: any, value2: any) => boolean, <T extends object>(target: T, handler: ProxyHandler<T>) => T, (x: unknown) => boolean, WeakMap<object, [version: number, snap: unknown]>, CreateSnapshot, WeakMap<object, object>, [number, number]]; | ||
export declare const unstable_getInternalStates: () => { | ||
proxyStateMap: WeakMap<object, ProxyState>; | ||
refSet: WeakSet<WeakKey>; | ||
snapCache: WeakMap<object, [version: number, snap: unknown]>; | ||
versionHolder: [number, number]; | ||
proxyCache: WeakMap<object, object>; | ||
}; | ||
export declare function unstable_replaceInternalFunction(name: 'objectIs', fn: (prev: typeof objectIs) => typeof objectIs): void; | ||
export declare function unstable_replaceInternalFunction(name: 'newProxy', fn: (prev: typeof newProxy) => typeof newProxy): void; | ||
export declare function unstable_replaceInternalFunction(name: 'canProxy', fn: (prev: typeof canProxy) => typeof canProxy): void; | ||
export declare function unstable_replaceInternalFunction(name: 'createSnapshot', fn: (prev: typeof createSnapshot) => typeof createSnapshot): void; | ||
export declare function unstable_replaceInternalFunction(name: 'createHandler', fn: (prev: typeof createHandler) => typeof createHandler): void; | ||
export {}; |
173
vanilla.js
@@ -6,5 +6,4 @@ 'use strict'; | ||
const isObject = (x) => typeof x === "object" && x !== null; | ||
const proxyStateMap = /* @__PURE__ */ new WeakMap(); | ||
const refSet = /* @__PURE__ */ new WeakSet(); | ||
const buildProxyFunction = (objectIs = Object.is, newProxy = (target, handler) => new Proxy(target, handler), canProxy = (x) => isObject(x) && !refSet.has(x) && (Array.isArray(x) || !(Symbol.iterator in x)) && !(x instanceof WeakMap) && !(x instanceof WeakSet) && !(x instanceof Error) && !(x instanceof Number) && !(x instanceof Date) && !(x instanceof String) && !(x instanceof RegExp) && !(x instanceof ArrayBuffer), snapCache = /* @__PURE__ */ new WeakMap(), createSnapshot = (target, version) => { | ||
const canProxyDefault = (x) => isObject(x) && !refSet.has(x) && (Array.isArray(x) || !(Symbol.iterator in x)) && !(x instanceof WeakMap) && !(x instanceof WeakSet) && !(x instanceof Error) && !(x instanceof Number) && !(x instanceof Date) && !(x instanceof String) && !(x instanceof RegExp) && !(x instanceof ArrayBuffer); | ||
const createSnapshotDefault = (target, version) => { | ||
const cache = snapCache.get(target); | ||
@@ -44,3 +43,56 @@ if ((cache == null ? void 0 : cache[0]) === version) { | ||
return Object.preventExtensions(snap); | ||
}, proxyCache = /* @__PURE__ */ new WeakMap(), versionHolder = [1, 1], proxyFunction = (baseObject) => { | ||
}; | ||
const createHandlerDefault = (isInitializing, addPropListener, removePropListener, notifyUpdate) => ({ | ||
deleteProperty(target, prop) { | ||
const prevValue = Reflect.get(target, prop); | ||
removePropListener(prop); | ||
const deleted = Reflect.deleteProperty(target, prop); | ||
if (deleted) { | ||
notifyUpdate(["delete", [prop], prevValue]); | ||
} | ||
return deleted; | ||
}, | ||
set(target, prop, value, receiver) { | ||
const hasPrevValue = !isInitializing() && Reflect.has(target, prop); | ||
const prevValue = Reflect.get(target, prop, receiver); | ||
if (hasPrevValue && (objectIs(prevValue, value) || proxyCache.has(value) && objectIs(prevValue, proxyCache.get(value)))) { | ||
return true; | ||
} | ||
removePropListener(prop); | ||
if (isObject(value)) { | ||
value = proxyCompare.getUntracked(value) || value; | ||
} | ||
let nextValue = value; | ||
if (value instanceof Promise) { | ||
value.then((v) => { | ||
value.status = "fulfilled"; | ||
value.value = v; | ||
notifyUpdate(["resolve", [prop], v]); | ||
}).catch((e) => { | ||
value.status = "rejected"; | ||
value.reason = e; | ||
notifyUpdate(["reject", [prop], e]); | ||
}); | ||
} else { | ||
if (!proxyStateMap.has(value) && canProxy(value)) { | ||
nextValue = proxy(value); | ||
} | ||
addPropListener(prop, nextValue); | ||
} | ||
Reflect.set(target, prop, nextValue, receiver); | ||
notifyUpdate(["set", [prop], value, prevValue]); | ||
return true; | ||
} | ||
}); | ||
const proxyStateMap = /* @__PURE__ */ new WeakMap(); | ||
const refSet = /* @__PURE__ */ new WeakSet(); | ||
const snapCache = /* @__PURE__ */ new WeakMap(); | ||
const versionHolder = [1, 1]; | ||
const proxyCache = /* @__PURE__ */ new WeakMap(); | ||
let objectIs = Object.is; | ||
let newProxy = (target, handler) => new Proxy(target, handler); | ||
let canProxy = canProxyDefault; | ||
let createSnapshot = createSnapshotDefault; | ||
let createHandler = createHandlerDefault; | ||
function proxy(baseObject = {}) { | ||
if (!isObject(baseObject)) { | ||
@@ -87,3 +139,3 @@ throw new Error("object required"); | ||
if (listeners.size) { | ||
const remove = propProxyState[3](createPropListener(prop)); | ||
const remove = propProxyState[2](createPropListener(prop)); | ||
propProxyStates.set(prop, [propProxyState, remove]); | ||
@@ -110,3 +162,3 @@ } else { | ||
} | ||
const remove = propProxyState[3](createPropListener(prop)); | ||
const remove = propProxyState[2](createPropListener(prop)); | ||
propProxyStates.set(prop, [propProxyState, remove]); | ||
@@ -129,52 +181,11 @@ }); | ||
let initializing = true; | ||
const handler = { | ||
deleteProperty(target, prop) { | ||
const prevValue = Reflect.get(target, prop); | ||
removePropListener(prop); | ||
const deleted = Reflect.deleteProperty(target, prop); | ||
if (deleted) { | ||
notifyUpdate(["delete", [prop], prevValue]); | ||
} | ||
return deleted; | ||
}, | ||
set(target, prop, value, receiver) { | ||
const hasPrevValue = !initializing && Reflect.has(target, prop); | ||
const prevValue = Reflect.get(target, prop, receiver); | ||
if (hasPrevValue && (objectIs(prevValue, value) || proxyCache.has(value) && objectIs(prevValue, proxyCache.get(value)))) { | ||
return true; | ||
} | ||
removePropListener(prop); | ||
if (isObject(value)) { | ||
value = proxyCompare.getUntracked(value) || value; | ||
} | ||
let nextValue = value; | ||
if (value instanceof Promise) { | ||
value.then((v) => { | ||
value.status = "fulfilled"; | ||
value.value = v; | ||
notifyUpdate(["resolve", [prop], v]); | ||
}).catch((e) => { | ||
value.status = "rejected"; | ||
value.reason = e; | ||
notifyUpdate(["reject", [prop], e]); | ||
}); | ||
} else { | ||
if (!proxyStateMap.has(value) && canProxy(value)) { | ||
nextValue = proxyFunction(value); | ||
} | ||
addPropListener(prop, nextValue); | ||
} | ||
Reflect.set(target, prop, nextValue, receiver); | ||
notifyUpdate(["set", [prop], value, prevValue]); | ||
return true; | ||
} | ||
}; | ||
const handler = createHandler( | ||
() => initializing, | ||
addPropListener, | ||
removePropListener, | ||
notifyUpdate | ||
); | ||
const proxyObject = newProxy(baseObject, handler); | ||
proxyCache.set(baseObject, proxyObject); | ||
const proxyState = [ | ||
baseObject, | ||
ensureVersion, | ||
createSnapshot, | ||
addListener | ||
]; | ||
const proxyState = [baseObject, ensureVersion, addListener]; | ||
proxyStateMap.set(proxyObject, proxyState); | ||
@@ -192,20 +203,2 @@ Reflect.ownKeys(baseObject).forEach((key) => { | ||
return proxyObject; | ||
}) => [ | ||
// public functions | ||
proxyFunction, | ||
// shared state | ||
proxyStateMap, | ||
refSet, | ||
// internal things | ||
objectIs, | ||
newProxy, | ||
canProxy, | ||
snapCache, | ||
createSnapshot, | ||
proxyCache, | ||
versionHolder | ||
]; | ||
const [defaultProxyFunction] = buildProxyFunction(); | ||
function proxy(baseObject = {}) { | ||
return defaultProxyFunction(baseObject); | ||
} | ||
@@ -223,3 +216,3 @@ function getVersion(proxyObject) { | ||
const ops = []; | ||
const addListener = proxyState[3]; | ||
const addListener = proxyState[2]; | ||
let isListenerActive = false; | ||
@@ -253,3 +246,3 @@ const listener = (op) => { | ||
} | ||
const [target, ensureVersion, createSnapshot] = proxyState; | ||
const [target, ensureVersion] = proxyState; | ||
return createSnapshot(target, ensureVersion()); | ||
@@ -261,3 +254,30 @@ } | ||
} | ||
const unstable_buildProxyFunction = buildProxyFunction; | ||
const unstable_getInternalStates = () => ({ | ||
proxyStateMap, | ||
refSet, | ||
snapCache, | ||
versionHolder, | ||
proxyCache | ||
}); | ||
function unstable_replaceInternalFunction(name, fn) { | ||
switch (name) { | ||
case "objectIs": | ||
objectIs = fn(objectIs); | ||
break; | ||
case "newProxy": | ||
newProxy = fn(newProxy); | ||
break; | ||
case "canProxy": | ||
canProxy = fn(canProxy); | ||
break; | ||
case "createSnapshot": | ||
createSnapshot = fn(createSnapshot); | ||
break; | ||
case "createHandler": | ||
createHandler = fn(createHandler); | ||
break; | ||
default: | ||
throw new Error("unknown function"); | ||
} | ||
} | ||
@@ -269,2 +289,3 @@ exports.getVersion = getVersion; | ||
exports.subscribe = subscribe; | ||
exports.unstable_buildProxyFunction = unstable_buildProxyFunction; | ||
exports.unstable_getInternalStates = unstable_getInternalStates; | ||
exports.unstable_replaceInternalFunction = unstable_replaceInternalFunction; |
@@ -158,3 +158,3 @@ 'use strict'; | ||
if (!defaultRefSet) { | ||
defaultRefSet = vanilla.unstable_buildProxyFunction()[2]; | ||
defaultRefSet = vanilla.unstable_getInternalStates().refSet; | ||
} | ||
@@ -161,0 +161,0 @@ return defaultRefSet; |
@@ -30,3 +30,3 @@ /** | ||
export declare function proxyMap<K, V>(entries?: Iterable<readonly [K, V]> | null): Map<K, V> & { | ||
$$valtioSnapshot: Omit<Map<K, V>, 'set' | 'delete' | 'clear'>; | ||
$$valtioSnapshot: Omit<Map<K, V>, "set" | "delete" | "clear">; | ||
}; |
@@ -17,3 +17,3 @@ /** | ||
export declare function proxySet<T>(initialValues?: Iterable<T> | null): Set<T> & { | ||
$$valtioSnapshot: Omit<Set<T>, 'add' | 'delete' | 'clear'>; | ||
$$valtioSnapshot: Omit<Set<T>, "add" | "delete" | "clear">; | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
76806
1621
393