diff --git a/package.json b/package.json index 24373260..9c80940c 100644 --- a/package.json +++ b/package.json @@ -104,8 +104,7 @@ }, "homepage": "https://github.com/pmndrs/valtio", "dependencies": { - "proxy-compare": "2.5.1", - "derive-valtio": "0.1.0" + "proxy-compare": "2.5.1" }, "devDependencies": { "@babel/core": "^7.23.2", diff --git a/src/vanilla/utils.ts b/src/vanilla/utils.ts index 7c2c59b2..43b71f3a 100644 --- a/src/vanilla/utils.ts +++ b/src/vanilla/utils.ts @@ -1,7 +1,6 @@ export { subscribeKey } from './utils/subscribeKey.ts' export { watch } from './utils/watch.ts' export { devtools } from './utils/devtools.ts' -export { derive, underive, unstable_deriveSubscriptions } from 'derive-valtio' export { deepClone } from './utils/deepClone.ts' export { proxyWithHistory } from './utils/proxyWithHistory.ts' export { proxySet } from './utils/proxySet.ts' diff --git a/tests/derive.test.tsx b/tests/derive.test.tsx deleted file mode 100644 index b0610f23..00000000 --- a/tests/derive.test.tsx +++ /dev/null @@ -1,501 +0,0 @@ -/// - -import ReactExports, { StrictMode, Suspense, useEffect, useRef } from 'react' -import { fireEvent, render } from '@testing-library/react' -import { describe, expect, it, vi } from 'vitest' -import { proxy, snapshot, subscribe, useSnapshot } from 'valtio' -import { derive, underive } from 'valtio/utils' - -type DeriveGet = (proxyObject: T) => T - -const sleep = (ms: number) => - new Promise((resolve) => { - setTimeout(resolve, ms) - }) - -const { use } = ReactExports -const use2 = (x: T): Awaited => (x instanceof Promise ? use(x) : x) - -it('basic derive', async () => { - const computeDouble = vi.fn((x: number) => x * 2) - const state = proxy({ - text: '', - count: 0, - }) - const derived = derive({ - doubled: (get) => computeDouble(get(state).count), - }) - - const callback = vi.fn() - subscribe(derived, callback) - - expect(snapshot(derived)).toMatchObject({ doubled: 0 }) - expect(computeDouble).toBeCalledTimes(1) - expect(callback).toBeCalledTimes(0) - - state.count += 1 - await Promise.resolve() - expect(snapshot(derived)).toMatchObject({ doubled: 2 }) - expect(computeDouble).toBeCalledTimes(2) - await Promise.resolve() - expect(callback).toBeCalledTimes(1) - - state.text = 'a' - await Promise.resolve() - expect(snapshot(derived)).toMatchObject({ doubled: 2 }) - expect(computeDouble).toBeCalledTimes(3) - await Promise.resolve() - expect(callback).toBeCalledTimes(1) -}) - -it('derive another proxy', async () => { - const computeDouble = vi.fn((x: number) => x * 2) - const state = proxy({ - text: '', - count: 0, - }) - const anotherState = proxy({}) - derive( - { - doubled: (get) => computeDouble(get(state).count), - }, - { - proxy: anotherState, - }, - ) - - const callback = vi.fn() - subscribe(anotherState, callback) - - expect(snapshot(anotherState)).toMatchObject({ doubled: 0 }) - expect(computeDouble).toBeCalledTimes(1) - expect(callback).toBeCalledTimes(0) - - state.count += 1 - await Promise.resolve() - expect(snapshot(anotherState)).toMatchObject({ doubled: 2 }) - expect(computeDouble).toBeCalledTimes(2) - await Promise.resolve() - expect(callback).toBeCalledTimes(1) - - state.text = 'a' - await Promise.resolve() - expect(snapshot(anotherState)).toMatchObject({ doubled: 2 }) - expect(computeDouble).toBeCalledTimes(3) - await Promise.resolve() - expect(callback).toBeCalledTimes(1) -}) - -it('derive with self', async () => { - const computeDouble = vi.fn((x: number) => x * 2) - const state = proxy({ - text: '', - count: 0, - }) - derive( - { - doubled: (get) => computeDouble(get(state).count), - }, - { - proxy: state, - }, - ) - - const callback = vi.fn() - subscribe(state, callback) - - expect(snapshot(state)).toMatchObject({ text: '', count: 0, doubled: 0 }) - expect(computeDouble).toBeCalledTimes(1) - expect(callback).toBeCalledTimes(0) - - state.count += 1 - await Promise.resolve() - expect(snapshot(state)).toMatchObject({ text: '', count: 1, doubled: 2 }) - expect(computeDouble).toBeCalledTimes(2) - await Promise.resolve() - expect(callback).toBeCalledTimes(1) - - state.text = 'a' - await Promise.resolve() - expect(snapshot(state)).toMatchObject({ text: 'a', count: 1, doubled: 2 }) - expect(computeDouble).toBeCalledTimes(3) - await Promise.resolve() - expect(callback).toBeCalledTimes(2) -}) - -it('derive with two dependencies', async () => { - const computeSum = vi.fn((x: number, y: number) => x + y) - const state1 = proxy({ count: 1 }) - const state2 = proxy({ count: 10 }) - const derived = derive({ - sum: (get) => computeSum(get(state1).count, get(state2).count), - }) - - const callback = vi.fn() - subscribe(derived, callback) - - expect(snapshot(derived)).toMatchObject({ sum: 11 }) - expect(computeSum).toBeCalledTimes(1) - expect(callback).toBeCalledTimes(0) - - state1.count += 1 - await Promise.resolve() - expect(snapshot(derived)).toMatchObject({ sum: 12 }) - expect(computeSum).toBeCalledTimes(2) - await Promise.resolve() - expect(callback).toBeCalledTimes(1) - - state1.count += 1 - state2.count += 10 - await Promise.resolve() - expect(snapshot(derived)).toMatchObject({ sum: 23 }) - expect(computeSum).toBeCalledTimes(3) - await Promise.resolve() - expect(callback).toBeCalledTimes(2) -}) - -it.skipIf(typeof use === 'undefined')('async derive', async () => { - const state = proxy({ count: 0 }) - derive( - { - delayedCount: async (get) => { - await sleep(300) - return get(state).count + 1 - }, - }, - { proxy: state }, - ) - - const Counter = () => { - const snap = useSnapshot( - state as { count: number; delayedCount: Promise }, - ) - return ( - <> -
- count: {snap.count}, delayedCount: {use2(snap.delayedCount)} -
- - - ) - } - - const { getByText, findByText } = render( - - - - - , - ) - - await findByText('loading') - await findByText('count: 0, delayedCount: 1') - - fireEvent.click(getByText('button')) - await findByText('loading') - await findByText('count: 1, delayedCount: 2') -}) - -it('nested emulation with derive', async () => { - const computeDouble = vi.fn((x: number) => x * 2) - const state = proxy({ text: '', math: { count: 0 } }) - derive( - { - doubled: (get) => computeDouble(get(state.math).count), - }, - { proxy: state.math, sync: true }, - ) - - const callback = vi.fn() - subscribe(state, callback) - - expect(snapshot(state)).toMatchObject({ - text: '', - math: { count: 0, doubled: 0 }, - }) - expect(computeDouble).toBeCalledTimes(1) - expect(callback).toBeCalledTimes(0) - - state.math.count += 1 - await Promise.resolve() - expect(snapshot(state)).toMatchObject({ - text: '', - math: { count: 1, doubled: 2 }, - }) - expect(computeDouble).toBeCalledTimes(2) - await Promise.resolve() - expect(callback).toBeCalledTimes(1) - - state.text = 'a' - await Promise.resolve() - expect(snapshot(state)).toMatchObject({ - text: 'a', - math: { count: 1, doubled: 2 }, - }) - expect(computeDouble).toBeCalledTimes(2) - await Promise.resolve() - expect(callback).toBeCalledTimes(2) -}) - -it('derive with array.pop', async () => { - const state = proxy({ - arr: [{ n: 1 }, { n: 2 }, { n: 3 }], - }) - derive( - { - nums: (get) => get(state.arr).map((item) => item.n), - }, - { proxy: state }, - ) - - expect(snapshot(state)).toMatchObject({ - arr: [{ n: 1 }, { n: 2 }, { n: 3 }], - nums: [1, 2, 3], - }) - - state.arr.pop() - await Promise.resolve() - expect(snapshot(state)).toMatchObject({ - arr: [{ n: 1 }, { n: 2 }], - nums: [1, 2], - }) -}) - -it('basic underive', async () => { - const computeDouble = vi.fn((x: number) => x * 2) - const state = proxy({ count: 0 }) - const derived = derive({ - doubled: (get) => computeDouble(get(state).count), - }) - - const callback = vi.fn() - subscribe(derived, callback) - - expect(snapshot(derived)).toMatchObject({ doubled: 0 }) - expect(computeDouble).toBeCalledTimes(1) - expect(callback).toBeCalledTimes(0) - - state.count += 1 - await Promise.resolve() - expect(snapshot(derived)).toMatchObject({ doubled: 2 }) - expect(computeDouble).toBeCalledTimes(2) - await Promise.resolve() - expect(callback).toBeCalledTimes(1) - - underive(derived) - - state.count += 1 - await Promise.resolve() - expect(snapshot(derived)).toMatchObject({ doubled: 2 }) - expect(computeDouble).toBeCalledTimes(2) - await Promise.resolve() - expect(callback).toBeCalledTimes(1) -}) - -describe('glitch free', () => { - it('basic (#296)', async () => { - const state = proxy({ value: 0 }) - const derived1 = derive({ value: (get) => get(state).value }) - const derived2 = derive({ value: (get) => get(derived1).value }) - const computeValue = vi.fn((get: DeriveGet) => { - const v0 = get(state).value - const v1 = get(derived1).value - const v2 = get(derived2).value - return `v0: ${v0}, v1: ${v1}, v2: ${v2}` - }) - const derived3 = derive({ value: computeValue }) - - const App = () => { - const snap = useSnapshot(derived3) - const commitsRef = useRef(1) - useEffect(() => { - commitsRef.current += 1 - }) - return ( - <> - value: {snap.value} (commits: {commitsRef.current}) - - - ) - } - - const { getByText, findByText } = render( - <> - - , - ) - - await findByText('value: v0: 0, v1: 0, v2: 0 (commits: 1)') - expect(computeValue).toBeCalledTimes(1) - - fireEvent.click(getByText('button')) - await findByText('value: v0: 1, v1: 1, v2: 1 (commits: 2)') - expect(computeValue).toBeCalledTimes(2) - }) - - it('same value', async () => { - const state = proxy({ value: 0 }) - const derived1 = derive({ - value: (get) => get(state).value * 0, - }) - const derived2 = derive({ - value: (get) => get(derived1).value * 0, - }) - const computeValue = vi.fn((get: DeriveGet) => { - const v0 = get(state).value - const v1 = get(derived1).value - const v2 = get(derived2).value - return v0 + (v1 - v2) - }) - const derived3 = derive({ - value: (get) => computeValue(get), - }) - - const App = () => { - const snap = useSnapshot(derived3) - return ( -
- value: {snap.value} - -
- ) - } - - const { getByText, findByText } = render( - - - , - ) - - await findByText('value: 0') - expect(computeValue).toBeCalledTimes(1) - - fireEvent.click(getByText('button')) - await findByText('value: 1') - expect(computeValue).toBeCalledTimes(2) - }) - - it('double chain', async () => { - const state = proxy({ value: 0 }) - const derived1 = derive({ - value: (get) => get(state).value, - }) - const derived2 = derive({ - value: (get) => get(derived1).value, - }) - const derived3 = derive({ - value: (get) => get(derived2).value, - }) - const computeValue = vi.fn((get: DeriveGet) => { - const v0 = get(state).value - const v1 = get(derived1).value - const v2 = get(derived2).value - const v3 = get(derived3).value - return v0 + (v1 - v2) + v3 * 0 - }) - const derived4 = derive({ - value: (get) => computeValue(get), - }) - - const App = () => { - const snap = useSnapshot(derived4) - return ( -
- value: {snap.value} - -
- ) - } - - const { getByText, findByText } = render( - - - , - ) - - await findByText('value: 0') - expect(computeValue).toBeCalledTimes(1) - - fireEvent.click(getByText('button')) - await findByText('value: 1') - expect(computeValue).toBeCalledTimes(2) - }) -}) - -describe('two derived properties', () => { - type State = { - a: number - derived1?: unknown - derived2?: unknown - } - - it('two derived properties both returning primitive values (#349)', async () => { - const state: State = proxy({ a: 1 }) - derive( - { - derived1: (get) => { - get(state).a - return 1 - }, - }, - { proxy: state }, - ) - derive( - { - derived2: (get) => { - get(state).a - return 1 - }, - }, - { proxy: state }, - ) - await Promise.resolve() - expect(state.derived1).toBeDefined() - expect(state.derived2).toBeDefined() - }) - - it('two derived properties both returning non primitive values, defined at the same time (#349)', async () => { - const state: State = proxy({ a: 1 }) - derive( - { - derived1: (get) => { - get(state).a - return {} - }, - derived2: (get) => { - get(state).a - return {} - }, - }, - { proxy: state }, - ) - await Promise.resolve() - expect(state.derived1).toBeDefined() - expect(state.derived2).toBeDefined() - }) - - it('two derived properties both returning non primitive values (#349)', async () => { - const state: State = proxy({ a: 1 }) - derive( - { - derived1: (get) => { - get(state).a - return {} - }, - }, - { proxy: state }, - ) - derive( - { - derived2: (get) => { - get(state).a - return {} - }, - }, - { proxy: state }, - ) - await Promise.resolve() - expect(state.derived1).toBeDefined() - expect(state.derived2).toBeDefined() - }) -}) diff --git a/yarn.lock b/yarn.lock index 425392e3..f4f5899a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2322,11 +2322,6 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -derive-valtio@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/derive-valtio/-/derive-valtio-0.1.0.tgz#4b9fb393dfefccfef15fcbbddd745dd22d5d63d7" - integrity sha512-OCg2UsLbXK7GmmpzMXhYkdO64vhJ1ROUUGaTFyHjVwEdMEcTTRj7W1TxLbSBxdY8QLBPCcp66MTyaSy0RpO17A== - diff-sequences@^29.4.3: version "29.6.3" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921"