Comparing version 0.6.3 to 0.7.0
280
index.js
@@ -1,4 +0,8 @@ | ||
import { useRef, useState, useEffect, useReducer, useCallback, useMemo, useLayoutEffect, useDebugValue } from 'react'; | ||
import { markToTrack, getUntrackedObject, isDeepChanged, createDeepProxy, affectedToPathList } from 'proxy-compare'; | ||
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
var react = require('react'); | ||
var proxyCompare = require('proxy-compare'); | ||
/* | ||
@@ -10,24 +14,31 @@ export { | ||
*/ | ||
const TARGET = Symbol(); | ||
const GET_VERSION = Symbol(); | ||
const createMutableSource = (target, getVersion) => ({ | ||
[TARGET]: target, | ||
[GET_VERSION]: getVersion | ||
}); | ||
const useMutableSource = (source, getSnapshot, subscribe) => { | ||
const lastVersion = useRef(0); | ||
const currentVersion = source[GET_VERSION](source[TARGET]); | ||
const [state, setState] = useState(() => [ | ||
/* [0] */ | ||
source, | ||
/* [1] */ | ||
getSnapshot, | ||
/* [2] */ | ||
subscribe, | ||
/* [3] */ | ||
currentVersion, | ||
/* [4] */ | ||
getSnapshot(source[TARGET])]); | ||
let currentSnapshot = state[4]; | ||
var TARGET = Symbol(); | ||
var GET_VERSION = Symbol(); | ||
var createMutableSource = function createMutableSource(target, getVersion) { | ||
var _ref; | ||
return _ref = {}, _ref[TARGET] = target, _ref[GET_VERSION] = getVersion, _ref; | ||
}; | ||
var useMutableSource = function useMutableSource(source, getSnapshot, subscribe) { | ||
var lastVersion = react.useRef(0); | ||
var currentVersion = source[GET_VERSION](source[TARGET]); | ||
var _useState = react.useState(function () { | ||
return [ | ||
/* [0] */ | ||
source, | ||
/* [1] */ | ||
getSnapshot, | ||
/* [2] */ | ||
subscribe, | ||
/* [3] */ | ||
currentVersion, | ||
/* [4] */ | ||
getSnapshot(source[TARGET])]; | ||
}), | ||
state = _useState[0], | ||
setState = _useState[1]; | ||
var currentSnapshot = state[4]; | ||
if (state[0] !== source || state[1] !== getSnapshot || state[2] !== subscribe || currentVersion !== state[3] && currentVersion !== lastVersion.current) { | ||
@@ -48,6 +59,6 @@ currentSnapshot = getSnapshot(source[TARGET]); | ||
useEffect(() => { | ||
let didUnsubscribe = false; | ||
react.useEffect(function () { | ||
var didUnsubscribe = false; | ||
const checkForUpdates = () => { | ||
var checkForUpdates = function checkForUpdates() { | ||
if (didUnsubscribe) { | ||
@@ -57,6 +68,6 @@ return; | ||
const nextVersion = source[GET_VERSION](source[TARGET]); | ||
var nextVersion = source[GET_VERSION](source[TARGET]); | ||
lastVersion.current = nextVersion; | ||
const nextSnapshot = getSnapshot(source[TARGET]); | ||
setState(prev => { | ||
var nextSnapshot = getSnapshot(source[TARGET]); | ||
setState(function (prev) { | ||
if (prev[0] !== source || prev[1] !== getSnapshot || prev[2] !== subscribe) { | ||
@@ -84,5 +95,5 @@ return prev; | ||
const unsubscribe = subscribe(source[TARGET], checkForUpdates); | ||
var unsubscribe = subscribe(source[TARGET], checkForUpdates); | ||
checkForUpdates(); | ||
return () => { | ||
return function () { | ||
didUnsubscribe = true; | ||
@@ -95,9 +106,9 @@ unsubscribe(); | ||
const VERSION = Symbol(); | ||
const LISTENERS = Symbol(); | ||
const SNAPSHOT = Symbol(); | ||
const PROMISE_RESULT = Symbol(); | ||
const PROMISE_ERROR = Symbol(); | ||
const refSet = new WeakSet(); | ||
const ref = o => { | ||
var VERSION = Symbol(); | ||
var LISTENERS = Symbol(); | ||
var SNAPSHOT = Symbol(); | ||
var PROMISE_RESULT = Symbol(); | ||
var PROMISE_ERROR = Symbol(); | ||
var refSet = new WeakSet(); | ||
var ref = function ref(o) { | ||
refSet.add(o); | ||
@@ -107,8 +118,14 @@ return o; | ||
const isSupportedObject = x => typeof x === 'object' && x !== null && (Array.isArray(x) || !x[Symbol.iterator]) && !(x instanceof WeakMap) && !(x instanceof WeakSet) && !(x instanceof Error) && !(x instanceof Number) && !(x instanceof Date) && !(x instanceof String) && !(x instanceof RegExp) && !(x instanceof ArrayBuffer); | ||
var isSupportedObject = function isSupportedObject(x) { | ||
return typeof x === 'object' && x !== null && (Array.isArray(x) || !x[Symbol.iterator]) && !(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 proxyCache = new WeakMap(); | ||
let globalVersion = 1; | ||
const snapshotCache = new WeakMap(); | ||
const proxy = (initialObject = {}) => { | ||
var proxyCache = new WeakMap(); | ||
var globalVersion = 1; | ||
var snapshotCache = new WeakMap(); | ||
var proxy = function proxy(initialObject) { | ||
if (initialObject === void 0) { | ||
initialObject = {}; | ||
} | ||
if (!isSupportedObject(initialObject)) { | ||
@@ -122,6 +139,6 @@ throw new Error('unsupported object type'); | ||
let version = globalVersion; | ||
const listeners = new Set(); | ||
var version = globalVersion; | ||
var listeners = new Set(); | ||
const notifyUpdate = nextVersion => { | ||
var notifyUpdate = function notifyUpdate(nextVersion) { | ||
if (!nextVersion) { | ||
@@ -133,9 +150,11 @@ nextVersion = ++globalVersion; | ||
version = nextVersion; | ||
listeners.forEach(listener => listener(nextVersion)); | ||
listeners.forEach(function (listener) { | ||
return listener(nextVersion); | ||
}); | ||
} | ||
}; | ||
const baseObject = Array.isArray(initialObject) ? [] : Object.create(Object.getPrototypeOf(initialObject)); | ||
const p = new Proxy(baseObject, { | ||
get(target, prop, receiver) { | ||
var baseObject = Array.isArray(initialObject) ? [] : Object.create(Object.getPrototypeOf(initialObject)); | ||
var p = new Proxy(baseObject, { | ||
get: function get(target, prop, receiver) { | ||
if (prop === VERSION) { | ||
@@ -150,3 +169,3 @@ return version; | ||
if (prop === SNAPSHOT) { | ||
const cache = snapshotCache.get(receiver); | ||
var cache = snapshotCache.get(receiver); | ||
@@ -157,34 +176,34 @@ if (cache && cache.version === version) { | ||
const snapshot = Array.isArray(target) ? [] : Object.create(Object.getPrototypeOf(target)); | ||
markToTrack(snapshot, true); // mark to track | ||
var _snapshot = Array.isArray(target) ? [] : Object.create(Object.getPrototypeOf(target)); | ||
proxyCompare.markToTrack(_snapshot, true); // mark to track | ||
snapshotCache.set(receiver, { | ||
version, | ||
snapshot | ||
version: version, | ||
snapshot: _snapshot | ||
}); | ||
Reflect.ownKeys(target).forEach(key => { | ||
const value = target[key]; | ||
Reflect.ownKeys(target).forEach(function (key) { | ||
var value = target[key]; | ||
if (refSet.has(value)) { | ||
markToTrack(value, false); // mark not to track | ||
proxyCompare.markToTrack(value, false); // mark not to track | ||
snapshot[key] = value; | ||
_snapshot[key] = value; | ||
} else if (!isSupportedObject(value)) { | ||
snapshot[key] = value; | ||
_snapshot[key] = value; | ||
} else if (value instanceof Promise) { | ||
if (PROMISE_RESULT in value) { | ||
snapshot[key] = value[PROMISE_RESULT]; | ||
_snapshot[key] = value[PROMISE_RESULT]; | ||
} else { | ||
const errorOrPromise = value[PROMISE_ERROR] || value; | ||
Object.defineProperty(snapshot, key, { | ||
get() { | ||
var errorOrPromise = value[PROMISE_ERROR] || value; | ||
Object.defineProperty(_snapshot, key, { | ||
get: function get() { | ||
throw errorOrPromise; | ||
} | ||
}); | ||
} | ||
} else if (value[VERSION]) { | ||
snapshot[key] = value[SNAPSHOT]; | ||
_snapshot[key] = value[SNAPSHOT]; | ||
} else { | ||
snapshot[key] = value; | ||
_snapshot[key] = value; | ||
} | ||
@@ -194,6 +213,6 @@ }); | ||
if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { | ||
Object.freeze(snapshot); | ||
Object.freeze(_snapshot); | ||
} | ||
return snapshot; | ||
return _snapshot; | ||
} | ||
@@ -203,7 +222,6 @@ | ||
}, | ||
deleteProperty: function deleteProperty(target, prop) { | ||
var prevValue = target[prop]; | ||
var childListeners = prevValue && prevValue[LISTENERS]; | ||
deleteProperty(target, prop) { | ||
const prevValue = target[prop]; | ||
const childListeners = prevValue && prevValue[LISTENERS]; | ||
if (childListeners) { | ||
@@ -213,3 +231,3 @@ childListeners.delete(notifyUpdate); | ||
const deleted = Reflect.deleteProperty(target, prop); | ||
var deleted = Reflect.deleteProperty(target, prop); | ||
@@ -222,6 +240,5 @@ if (deleted) { | ||
}, | ||
set: function set(target, prop, value) { | ||
var prevValue = target[prop]; | ||
set(target, prop, value) { | ||
const prevValue = target[prop]; | ||
if (Object.is(prevValue, value)) { | ||
@@ -231,3 +248,3 @@ return true; | ||
const childListeners = prevValue && prevValue[LISTENERS]; | ||
var childListeners = prevValue && prevValue[LISTENERS]; | ||
@@ -241,6 +258,6 @@ if (childListeners) { | ||
} else if (value instanceof Promise) { | ||
target[prop] = value.then(v => { | ||
target[prop] = value.then(function (v) { | ||
target[prop][PROMISE_RESULT] = v; | ||
notifyUpdate(); | ||
}).catch(e => { | ||
}).catch(function (e) { | ||
target[prop][PROMISE_ERROR] = e; | ||
@@ -250,3 +267,3 @@ notifyUpdate(); | ||
} else { | ||
value = getUntrackedObject(value) || value; | ||
value = proxyCompare.getUntrackedObject(value) || value; | ||
@@ -265,7 +282,6 @@ if (value[LISTENERS]) { | ||
} | ||
}); | ||
proxyCache.set(initialObject, p); | ||
Reflect.ownKeys(initialObject).forEach(key => { | ||
const desc = Object.getOwnPropertyDescriptor(initialObject, key); | ||
Reflect.ownKeys(initialObject).forEach(function (key) { | ||
var desc = Object.getOwnPropertyDescriptor(initialObject, key); | ||
@@ -280,3 +296,3 @@ if (desc.get) { | ||
}; | ||
const getVersion = p => { | ||
var getVersion = function getVersion(p) { | ||
if (typeof process === 'object' && process.env.NODE_ENV !== 'production' && (!p || !p[VERSION])) { | ||
@@ -288,3 +304,3 @@ throw new Error('Please use proxy object'); | ||
}; | ||
const subscribe = (p, callback, notifyInSync) => { | ||
var subscribe = function subscribe(p, callback, notifyInSync) { | ||
if (typeof process === 'object' && process.env.NODE_ENV !== 'production' && (!p || !p[LISTENERS])) { | ||
@@ -294,5 +310,5 @@ throw new Error('Please use proxy object'); | ||
let pendingVersion = 0; | ||
var pendingVersion = 0; | ||
const listener = nextVersion => { | ||
var listener = function listener(nextVersion) { | ||
if (notifyInSync) { | ||
@@ -304,3 +320,3 @@ callback(); | ||
pendingVersion = nextVersion; | ||
Promise.resolve().then(() => { | ||
Promise.resolve().then(function () { | ||
if (nextVersion === pendingVersion) { | ||
@@ -313,7 +329,7 @@ callback(); | ||
p[LISTENERS].add(listener); | ||
return () => { | ||
return function () { | ||
p[LISTENERS].delete(listener); | ||
}; | ||
}; | ||
const snapshot = p => { | ||
var snapshot = function snapshot(p) { | ||
if (typeof process === 'object' && process.env.NODE_ENV !== 'production' && (!p || !p[SNAPSHOT])) { | ||
@@ -326,16 +342,16 @@ throw new Error('Please use proxy object'); | ||
const isSSR = typeof window === 'undefined' || /ServerSideRendering/.test(window.navigator && window.navigator.userAgent); | ||
const useIsomorphicLayoutEffect = isSSR ? useEffect : useLayoutEffect; | ||
var isSSR = typeof window === 'undefined' || /ServerSideRendering/.test(window.navigator && window.navigator.userAgent); | ||
var useIsomorphicLayoutEffect = isSSR ? react.useEffect : react.useLayoutEffect; | ||
const useAffectedDebugValue = (state, affected) => { | ||
const pathList = useRef(); | ||
useEffect(() => { | ||
pathList.current = affectedToPathList(state, affected); | ||
var useAffectedDebugValue = function useAffectedDebugValue(state, affected) { | ||
var pathList = react.useRef(); | ||
react.useEffect(function () { | ||
pathList.current = proxyCompare.affectedToPathList(state, affected); | ||
}); | ||
useDebugValue(pathList.current); | ||
react.useDebugValue(pathList.current); | ||
}; | ||
const mutableSourceCache = new WeakMap(); | ||
var mutableSourceCache = new WeakMap(); | ||
const getMutableSource = p => { | ||
var getMutableSource = function getMutableSource(p) { | ||
if (!mutableSourceCache.has(p)) { | ||
@@ -348,15 +364,19 @@ mutableSourceCache.set(p, createMutableSource(p, getVersion)); | ||
const useProxy = (p, options) => { | ||
const [, forceUpdate] = useReducer(c => c + 1, 0); | ||
const affected = new WeakMap(); | ||
const lastAffected = useRef(); | ||
const prevSnapshot = useRef(); | ||
const lastSnapshot = useRef(); | ||
useIsomorphicLayoutEffect(() => { | ||
var useProxy = function useProxy(p, options) { | ||
var _useReducer = react.useReducer(function (c) { | ||
return c + 1; | ||
}, 0), | ||
forceUpdate = _useReducer[1]; | ||
var affected = new WeakMap(); | ||
var lastAffected = react.useRef(); | ||
var prevSnapshot = react.useRef(); | ||
var lastSnapshot = react.useRef(); | ||
useIsomorphicLayoutEffect(function () { | ||
lastSnapshot.current = prevSnapshot.current = snapshot(p); | ||
}, [p]); | ||
useIsomorphicLayoutEffect(() => { | ||
useIsomorphicLayoutEffect(function () { | ||
lastAffected.current = affected; | ||
if (prevSnapshot.current !== lastSnapshot.current && isDeepChanged(prevSnapshot.current, lastSnapshot.current, affected, new WeakMap())) { | ||
if (prevSnapshot.current !== lastSnapshot.current && proxyCompare.isDeepChanged(prevSnapshot.current, lastSnapshot.current, affected, new WeakMap())) { | ||
prevSnapshot.current = lastSnapshot.current; | ||
@@ -366,19 +386,21 @@ forceUpdate(); | ||
}); | ||
const notifyInSync = options == null ? void 0 : options.sync; | ||
const sub = useCallback((p, cb) => subscribe(p, () => { | ||
const nextSnapshot = snapshot(p); | ||
lastSnapshot.current = nextSnapshot; | ||
var notifyInSync = options == null ? void 0 : options.sync; | ||
var sub = react.useCallback(function (p, cb) { | ||
return subscribe(p, function () { | ||
var nextSnapshot = snapshot(p); | ||
lastSnapshot.current = nextSnapshot; | ||
try { | ||
if (lastAffected.current && !isDeepChanged(prevSnapshot.current, nextSnapshot, lastAffected.current, new WeakMap())) { | ||
// not changed | ||
return; | ||
try { | ||
if (lastAffected.current && !proxyCompare.isDeepChanged(prevSnapshot.current, nextSnapshot, lastAffected.current, new WeakMap())) { | ||
// not changed | ||
return; | ||
} | ||
} catch (e) {// ignore if a promise or something is thrown | ||
} | ||
} catch (e) {// ignore if a promise or something is thrown | ||
} | ||
prevSnapshot.current = nextSnapshot; | ||
cb(); | ||
}, notifyInSync), [notifyInSync]); | ||
const currSnapshot = useMutableSource(getMutableSource(p), snapshot, sub); | ||
prevSnapshot.current = nextSnapshot; | ||
cb(); | ||
}, notifyInSync); | ||
}, [notifyInSync]); | ||
var currSnapshot = useMutableSource(getMutableSource(p), snapshot, sub); | ||
@@ -390,7 +412,13 @@ if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { | ||
const proxyCache = useMemo(() => new WeakMap(), []); // per-hook proxyCache | ||
var proxyCache = react.useMemo(function () { | ||
return new WeakMap(); | ||
}, []); // per-hook proxyCache | ||
return createDeepProxy(currSnapshot, affected, proxyCache); | ||
return proxyCompare.createDeepProxy(currSnapshot, affected, proxyCache); | ||
}; | ||
export { proxy, ref, snapshot, subscribe, useProxy }; | ||
exports.proxy = proxy; | ||
exports.ref = ref; | ||
exports.snapshot = snapshot; | ||
exports.subscribe = subscribe; | ||
exports.useProxy = useProxy; |
{ | ||
"name": "valtio", | ||
"private": false, | ||
"version": "0.6.3", | ||
"version": "0.7.0", | ||
"description": "💊 Valtio makes proxy-state simple for React and Vanilla", | ||
"main": "index.cjs.js", | ||
"module": "index.js", | ||
"main": "index.js", | ||
"module": "index.module.js", | ||
"types": "index.d.ts", | ||
@@ -12,17 +12,14 @@ "exports": { | ||
".": { | ||
"import": "./index.js", | ||
"require": "./index.cjs.js", | ||
"node": "./index.cjs.js", | ||
"import": "./index.module.js", | ||
"require": "./index.js", | ||
"types": "./index.d.ts" | ||
}, | ||
"./vanilla": { | ||
"import": "./vanilla.js", | ||
"require": "./vanilla.cjs.js", | ||
"node": "./vanilla.cjs.js", | ||
"import": "./vanilla.module.js", | ||
"require": "./vanilla.js", | ||
"types": "./vanilla.d.ts" | ||
}, | ||
"./utils": { | ||
"import": "./utils.js", | ||
"require": "./utils.cjs.js", | ||
"node": "./utils.cjs.js", | ||
"import": "./utils.module.js", | ||
"require": "./utils.js", | ||
"types": "./utils.d.ts" | ||
@@ -29,0 +26,0 @@ } |
@@ -68,3 +68,4 @@ <img src="logo.svg" alt="valtio"> | ||
To subscribe to a primitive value of state, consider [subscribeKey](./src/utils.ts#L28-L35) in utils. | ||
To subscribe to a primitive value of state, | ||
consider [subscribeKey](./src/utils.ts#L30-L37) in utils. | ||
@@ -155,3 +156,4 @@ #### Suspend your components | ||
You can use it locally in components. [Notes](./src/utils.ts#L5-L15) | ||
You can use it locally in components. | ||
[Notes](./src/utils.ts#L7-L17) | ||
@@ -164,1 +166,16 @@ ```jsx | ||
``` | ||
#### Proxy with computed | ||
You can have computed values with dependency tracking. This is for experts. | ||
[Notes](./src/utils.ts#121-L143) | ||
```js | ||
import { proxyWithComputed } from 'valtio/utils' | ||
const state = proxyWithComputed({ | ||
count: 1, | ||
}, { | ||
doubled: { get: snap => snap.count * 2 }, | ||
}) | ||
``` |
@@ -0,1 +1,2 @@ | ||
import type { NonPromise } from './vanilla'; | ||
/** | ||
@@ -14,3 +15,3 @@ * useLocalProxy | ||
*/ | ||
export declare const useLocalProxy: <T extends object>(init: T | (() => T)) => readonly [import("./vanilla").NonPromise<T>, T]; | ||
export declare const useLocalProxy: <T extends object>(init: T | (() => T)) => readonly [NonPromise<T>, T]; | ||
/** | ||
@@ -39,1 +40,30 @@ * subscribeKey | ||
export declare const devtools: <T extends object>(proxyObject: T, name?: string | undefined) => (() => void) | undefined; | ||
/** | ||
* proxyWithComputed | ||
* | ||
* This is to create a proxy with initial object and additional object, | ||
* which specifies getters for computed values with dependency tracking. | ||
* It also accepts optional setters for computed values. | ||
* | ||
* [Notes] | ||
* This is for expert users and not recommended for ordinary users. | ||
* Contradictory to its name, this is costly and overlaps with useProxy. | ||
* Do not try to optimize too early. It can worsen the performance. | ||
* Measurement and comparison will be very important. | ||
* | ||
* @example | ||
* import { proxyWithComputed } from 'valtio/utils' | ||
* const state = proxyWithComputed({ | ||
* count: 1, | ||
* }, { | ||
* doubled: snap => snap.count * 2, // getter only | ||
* tripled: { | ||
* get: snap => snap.count * 3, | ||
* set: (state, newValue) => { state.count = newValue / 3 } | ||
* }, // with optional setter | ||
* }) | ||
*/ | ||
export declare const proxyWithComputed: <T extends object, U extends object>(initialObject: T, computedFns: { [K in keyof U]: { | ||
get: (snap: NonPromise<T>) => U[K]; | ||
set?: ((state: T, newValue: U[K]) => void) | undefined; | ||
} | ((snap: NonPromise<T>) => U[K]); }) => T & U; |
134
utils.js
@@ -1,4 +0,9 @@ | ||
import { useRef } from 'react'; | ||
import { proxy, useProxy, subscribe, snapshot } from 'valtio'; | ||
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
var react = require('react'); | ||
var valtio = require('valtio'); | ||
var proxyCompare = require('proxy-compare'); | ||
/** | ||
@@ -18,11 +23,11 @@ * useLocalProxy | ||
const useLocalProxy = init => { | ||
const ref = useRef(); | ||
var useLocalProxy = function useLocalProxy(init) { | ||
var ref = react.useRef(); | ||
if (!ref.current) { | ||
const initialObject = typeof init === 'function' ? init() : init; | ||
ref.current = proxy(initialObject); | ||
var initialObject = typeof init === 'function' ? init() : init; | ||
ref.current = valtio.proxy(initialObject); | ||
} | ||
return [useProxy(ref.current), ref.current]; | ||
return [valtio.useProxy(ref.current), ref.current]; | ||
}; | ||
@@ -40,6 +45,6 @@ /** | ||
const subscribeKey = (proxyObject, key, callback) => { | ||
let prevValue = proxyObject[key]; | ||
return subscribe(proxyObject, () => { | ||
const nextValue = proxyObject[key]; | ||
var subscribeKey = function subscribeKey(proxyObject, key, callback) { | ||
var prevValue = proxyObject[key]; | ||
return valtio.subscribe(proxyObject, function () { | ||
var nextValue = proxyObject[key]; | ||
@@ -63,4 +68,4 @@ if (!Object.is(prevValue, nextValue)) { | ||
const devtools = (proxyObject, name) => { | ||
let extension; | ||
var devtools = function devtools(proxyObject, name) { | ||
var extension; | ||
@@ -79,14 +84,14 @@ try { | ||
let isTimeTraveling = false; | ||
const devtools = extension.connect({ | ||
name | ||
var isTimeTraveling = false; | ||
var devtools = extension.connect({ | ||
name: name | ||
}); | ||
const unsub1 = subscribe(proxyObject, () => { | ||
var unsub1 = valtio.subscribe(proxyObject, function () { | ||
if (isTimeTraveling) { | ||
isTimeTraveling = false; | ||
} else { | ||
devtools.send(`Update - ${new Date().toLocaleString()}`, snapshot(proxyObject)); | ||
devtools.send("Update - " + new Date().toLocaleString(), valtio.snapshot(proxyObject)); | ||
} | ||
}); | ||
const unsub2 = devtools.subscribe(message => { | ||
var unsub2 = devtools.subscribe(function (message) { | ||
var _message$payload3; | ||
@@ -101,12 +106,12 @@ | ||
const nextValue = JSON.parse(message.state); | ||
Object.keys(nextValue).forEach(key => { | ||
var nextValue = JSON.parse(message.state); | ||
Object.keys(nextValue).forEach(function (key) { | ||
proxyObject[key] = nextValue[key]; | ||
}); | ||
} else if (message.type === 'DISPATCH' && ((_message$payload3 = message.payload) == null ? void 0 : _message$payload3.type) === 'COMMIT') { | ||
devtools.init(snapshot(proxyObject)); | ||
devtools.init(valtio.snapshot(proxyObject)); | ||
} | ||
}); | ||
devtools.init(snapshot(proxyObject)); | ||
return () => { | ||
devtools.init(valtio.snapshot(proxyObject)); | ||
return function () { | ||
unsub1(); | ||
@@ -116,3 +121,82 @@ unsub2(); | ||
}; | ||
/** | ||
* proxyWithComputed | ||
* | ||
* This is to create a proxy with initial object and additional object, | ||
* which specifies getters for computed values with dependency tracking. | ||
* It also accepts optional setters for computed values. | ||
* | ||
* [Notes] | ||
* This is for expert users and not recommended for ordinary users. | ||
* Contradictory to its name, this is costly and overlaps with useProxy. | ||
* Do not try to optimize too early. It can worsen the performance. | ||
* Measurement and comparison will be very important. | ||
* | ||
* @example | ||
* import { proxyWithComputed } from 'valtio/utils' | ||
* const state = proxyWithComputed({ | ||
* count: 1, | ||
* }, { | ||
* doubled: snap => snap.count * 2, // getter only | ||
* tripled: { | ||
* get: snap => snap.count * 3, | ||
* set: (state, newValue) => { state.count = newValue / 3 } | ||
* }, // with optional setter | ||
* }) | ||
*/ | ||
export { devtools, subscribeKey, useLocalProxy }; | ||
var proxyWithComputed = function proxyWithComputed(initialObject, computedFns) { | ||
var NOTIFIER = Symbol(); | ||
Object.defineProperty(initialObject, NOTIFIER, { | ||
value: 0 | ||
}); | ||
Object.keys(computedFns).forEach(function (key) { | ||
var computedFn = computedFns[key]; | ||
var _ref = typeof computedFn === 'function' ? { | ||
get: computedFn | ||
} : computedFn, | ||
get = _ref.get, | ||
set = _ref.set; | ||
var computedValue; | ||
var prevSnapshot; | ||
var affected = new WeakMap(); | ||
var desc = {}; | ||
desc.get = function () { | ||
var nextSnapshot = valtio.snapshot(p); | ||
if (!prevSnapshot || proxyCompare.isDeepChanged(prevSnapshot, nextSnapshot, affected)) { | ||
affected = new WeakMap(); | ||
computedValue = get(proxyCompare.createDeepProxy(nextSnapshot, affected)); | ||
if (computedValue instanceof Promise) { | ||
computedValue.then(function (v) { | ||
computedValue = v; | ||
++p[NOTIFIER]; // HACK notify update | ||
}); // XXX no error handling | ||
} | ||
prevSnapshot = nextSnapshot; | ||
} | ||
return computedValue; | ||
}; | ||
if (set) { | ||
desc.set = function (newValue) { | ||
return set(p, newValue); | ||
}; | ||
} | ||
Object.defineProperty(initialObject, key, desc); | ||
}); | ||
var p = valtio.proxy(initialObject); | ||
return p; | ||
}; | ||
exports.devtools = devtools; | ||
exports.proxyWithComputed = proxyWithComputed; | ||
exports.subscribeKey = subscribeKey; | ||
exports.useLocalProxy = useLocalProxy; |
137
vanilla.js
@@ -1,10 +0,14 @@ | ||
import { markToTrack, getUntrackedObject } from 'proxy-compare'; | ||
'use strict'; | ||
const VERSION = Symbol(); | ||
const LISTENERS = Symbol(); | ||
const SNAPSHOT = Symbol(); | ||
const PROMISE_RESULT = Symbol(); | ||
const PROMISE_ERROR = Symbol(); | ||
const refSet = new WeakSet(); | ||
const ref = o => { | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
var proxyCompare = require('proxy-compare'); | ||
var VERSION = Symbol(); | ||
var LISTENERS = Symbol(); | ||
var SNAPSHOT = Symbol(); | ||
var PROMISE_RESULT = Symbol(); | ||
var PROMISE_ERROR = Symbol(); | ||
var refSet = new WeakSet(); | ||
var ref = function ref(o) { | ||
refSet.add(o); | ||
@@ -14,8 +18,14 @@ return o; | ||
const isSupportedObject = x => typeof x === 'object' && x !== null && (Array.isArray(x) || !x[Symbol.iterator]) && !(x instanceof WeakMap) && !(x instanceof WeakSet) && !(x instanceof Error) && !(x instanceof Number) && !(x instanceof Date) && !(x instanceof String) && !(x instanceof RegExp) && !(x instanceof ArrayBuffer); | ||
var isSupportedObject = function isSupportedObject(x) { | ||
return typeof x === 'object' && x !== null && (Array.isArray(x) || !x[Symbol.iterator]) && !(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 proxyCache = new WeakMap(); | ||
let globalVersion = 1; | ||
const snapshotCache = new WeakMap(); | ||
const proxy = (initialObject = {}) => { | ||
var proxyCache = new WeakMap(); | ||
var globalVersion = 1; | ||
var snapshotCache = new WeakMap(); | ||
var proxy = function proxy(initialObject) { | ||
if (initialObject === void 0) { | ||
initialObject = {}; | ||
} | ||
if (!isSupportedObject(initialObject)) { | ||
@@ -29,6 +39,6 @@ throw new Error('unsupported object type'); | ||
let version = globalVersion; | ||
const listeners = new Set(); | ||
var version = globalVersion; | ||
var listeners = new Set(); | ||
const notifyUpdate = nextVersion => { | ||
var notifyUpdate = function notifyUpdate(nextVersion) { | ||
if (!nextVersion) { | ||
@@ -40,9 +50,11 @@ nextVersion = ++globalVersion; | ||
version = nextVersion; | ||
listeners.forEach(listener => listener(nextVersion)); | ||
listeners.forEach(function (listener) { | ||
return listener(nextVersion); | ||
}); | ||
} | ||
}; | ||
const baseObject = Array.isArray(initialObject) ? [] : Object.create(Object.getPrototypeOf(initialObject)); | ||
const p = new Proxy(baseObject, { | ||
get(target, prop, receiver) { | ||
var baseObject = Array.isArray(initialObject) ? [] : Object.create(Object.getPrototypeOf(initialObject)); | ||
var p = new Proxy(baseObject, { | ||
get: function get(target, prop, receiver) { | ||
if (prop === VERSION) { | ||
@@ -57,3 +69,3 @@ return version; | ||
if (prop === SNAPSHOT) { | ||
const cache = snapshotCache.get(receiver); | ||
var cache = snapshotCache.get(receiver); | ||
@@ -64,34 +76,34 @@ if (cache && cache.version === version) { | ||
const snapshot = Array.isArray(target) ? [] : Object.create(Object.getPrototypeOf(target)); | ||
markToTrack(snapshot, true); // mark to track | ||
var _snapshot = Array.isArray(target) ? [] : Object.create(Object.getPrototypeOf(target)); | ||
proxyCompare.markToTrack(_snapshot, true); // mark to track | ||
snapshotCache.set(receiver, { | ||
version, | ||
snapshot | ||
version: version, | ||
snapshot: _snapshot | ||
}); | ||
Reflect.ownKeys(target).forEach(key => { | ||
const value = target[key]; | ||
Reflect.ownKeys(target).forEach(function (key) { | ||
var value = target[key]; | ||
if (refSet.has(value)) { | ||
markToTrack(value, false); // mark not to track | ||
proxyCompare.markToTrack(value, false); // mark not to track | ||
snapshot[key] = value; | ||
_snapshot[key] = value; | ||
} else if (!isSupportedObject(value)) { | ||
snapshot[key] = value; | ||
_snapshot[key] = value; | ||
} else if (value instanceof Promise) { | ||
if (PROMISE_RESULT in value) { | ||
snapshot[key] = value[PROMISE_RESULT]; | ||
_snapshot[key] = value[PROMISE_RESULT]; | ||
} else { | ||
const errorOrPromise = value[PROMISE_ERROR] || value; | ||
Object.defineProperty(snapshot, key, { | ||
get() { | ||
var errorOrPromise = value[PROMISE_ERROR] || value; | ||
Object.defineProperty(_snapshot, key, { | ||
get: function get() { | ||
throw errorOrPromise; | ||
} | ||
}); | ||
} | ||
} else if (value[VERSION]) { | ||
snapshot[key] = value[SNAPSHOT]; | ||
_snapshot[key] = value[SNAPSHOT]; | ||
} else { | ||
snapshot[key] = value; | ||
_snapshot[key] = value; | ||
} | ||
@@ -101,6 +113,6 @@ }); | ||
if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { | ||
Object.freeze(snapshot); | ||
Object.freeze(_snapshot); | ||
} | ||
return snapshot; | ||
return _snapshot; | ||
} | ||
@@ -110,7 +122,6 @@ | ||
}, | ||
deleteProperty: function deleteProperty(target, prop) { | ||
var prevValue = target[prop]; | ||
var childListeners = prevValue && prevValue[LISTENERS]; | ||
deleteProperty(target, prop) { | ||
const prevValue = target[prop]; | ||
const childListeners = prevValue && prevValue[LISTENERS]; | ||
if (childListeners) { | ||
@@ -120,3 +131,3 @@ childListeners.delete(notifyUpdate); | ||
const deleted = Reflect.deleteProperty(target, prop); | ||
var deleted = Reflect.deleteProperty(target, prop); | ||
@@ -129,6 +140,5 @@ if (deleted) { | ||
}, | ||
set: function set(target, prop, value) { | ||
var prevValue = target[prop]; | ||
set(target, prop, value) { | ||
const prevValue = target[prop]; | ||
if (Object.is(prevValue, value)) { | ||
@@ -138,3 +148,3 @@ return true; | ||
const childListeners = prevValue && prevValue[LISTENERS]; | ||
var childListeners = prevValue && prevValue[LISTENERS]; | ||
@@ -148,6 +158,6 @@ if (childListeners) { | ||
} else if (value instanceof Promise) { | ||
target[prop] = value.then(v => { | ||
target[prop] = value.then(function (v) { | ||
target[prop][PROMISE_RESULT] = v; | ||
notifyUpdate(); | ||
}).catch(e => { | ||
}).catch(function (e) { | ||
target[prop][PROMISE_ERROR] = e; | ||
@@ -157,3 +167,3 @@ notifyUpdate(); | ||
} else { | ||
value = getUntrackedObject(value) || value; | ||
value = proxyCompare.getUntrackedObject(value) || value; | ||
@@ -172,7 +182,6 @@ if (value[LISTENERS]) { | ||
} | ||
}); | ||
proxyCache.set(initialObject, p); | ||
Reflect.ownKeys(initialObject).forEach(key => { | ||
const desc = Object.getOwnPropertyDescriptor(initialObject, key); | ||
Reflect.ownKeys(initialObject).forEach(function (key) { | ||
var desc = Object.getOwnPropertyDescriptor(initialObject, key); | ||
@@ -187,3 +196,3 @@ if (desc.get) { | ||
}; | ||
const getVersion = p => { | ||
var getVersion = function getVersion(p) { | ||
if (typeof process === 'object' && process.env.NODE_ENV !== 'production' && (!p || !p[VERSION])) { | ||
@@ -195,3 +204,3 @@ throw new Error('Please use proxy object'); | ||
}; | ||
const subscribe = (p, callback, notifyInSync) => { | ||
var subscribe = function subscribe(p, callback, notifyInSync) { | ||
if (typeof process === 'object' && process.env.NODE_ENV !== 'production' && (!p || !p[LISTENERS])) { | ||
@@ -201,5 +210,5 @@ throw new Error('Please use proxy object'); | ||
let pendingVersion = 0; | ||
var pendingVersion = 0; | ||
const listener = nextVersion => { | ||
var listener = function listener(nextVersion) { | ||
if (notifyInSync) { | ||
@@ -211,3 +220,3 @@ callback(); | ||
pendingVersion = nextVersion; | ||
Promise.resolve().then(() => { | ||
Promise.resolve().then(function () { | ||
if (nextVersion === pendingVersion) { | ||
@@ -220,7 +229,7 @@ callback(); | ||
p[LISTENERS].add(listener); | ||
return () => { | ||
return function () { | ||
p[LISTENERS].delete(listener); | ||
}; | ||
}; | ||
const snapshot = p => { | ||
var snapshot = function snapshot(p) { | ||
if (typeof process === 'object' && process.env.NODE_ENV !== 'production' && (!p || !p[SNAPSHOT])) { | ||
@@ -233,2 +242,6 @@ throw new Error('Please use proxy object'); | ||
export { getVersion, proxy, ref, snapshot, subscribe }; | ||
exports.getVersion = getVersion; | ||
exports.proxy = proxy; | ||
exports.ref = ref; | ||
exports.snapshot = snapshot; | ||
exports.subscribe = subscribe; |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
179
58248
1505
1