From b6a7240e5b8e8fbbac3438c799bcec910a20b82b Mon Sep 17 00:00:00 2001 From: Daishi Kato Date: Thu, 15 Jul 2021 18:52:08 +0900 Subject: [PATCH] fix: support atom scope outside core (#589) --- .size-snapshot.json | 50 +++++++++++++++--------------- src/query.ts | 2 +- src/query/atomWithInfiniteQuery.ts | 16 +++++++--- src/query/atomWithQuery.ts | 16 +++++++--- src/query/queryClientAtom.ts | 6 +--- src/redux/atomWithStore.ts | 5 ++- src/urql/atomWithMutation.ts | 10 ++++-- src/urql/atomWithQuery.ts | 6 ++-- src/urql/atomWithSubscription.ts | 6 ++-- src/urql/clientAtom.ts | 8 ++--- src/utils/atomWithDefault.ts | 2 ++ src/utils/atomWithStorage.ts | 6 +++- src/utils/selectAtom.ts | 1 + src/utils/splitAtom.ts | 1 + src/valtio/atomWithProxy.ts | 6 +++- src/xstate/atomWithMachine.ts | 20 ++++++++++-- src/zustand/atomWithStore.ts | 6 +++- 17 files changed, 108 insertions(+), 59 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index b003628453..39d0462a0b 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -14,9 +14,9 @@ } }, "utils.js": { - "bundled": 13479, - "minified": 6775, - "gzipped": 2544, + "bundled": 13716, + "minified": 6895, + "gzipped": 2574, "treeshaked": { "rollup": { "code": 28, @@ -70,23 +70,23 @@ } }, "query.js": { - "bundled": 5321, - "minified": 2315, - "gzipped": 721, + "bundled": 5444, + "minified": 2279, + "gzipped": 710, "treeshaked": { "rollup": { - "code": 105, + "code": 80, "import_statements": 71 }, "webpack": { - "code": 1131 + "code": 1093 } } }, "xstate.js": { - "bundled": 2977, - "minified": 1314, - "gzipped": 653, + "bundled": 3565, + "minified": 1470, + "gzipped": 684, "treeshaked": { "rollup": { "code": 29, @@ -98,9 +98,9 @@ } }, "valtio.js": { - "bundled": 1235, - "minified": 598, - "gzipped": 335, + "bundled": 1333, + "minified": 642, + "gzipped": 350, "treeshaked": { "rollup": { "code": 37, @@ -112,9 +112,9 @@ } }, "zustand.js": { - "bundled": 549, - "minified": 262, - "gzipped": 188, + "bundled": 647, + "minified": 306, + "gzipped": 204, "treeshaked": { "rollup": { "code": 14, @@ -126,9 +126,9 @@ } }, "redux.js": { - "bundled": 458, - "minified": 220, - "gzipped": 167, + "bundled": 516, + "minified": 248, + "gzipped": 180, "treeshaked": { "rollup": { "code": 14, @@ -140,16 +140,16 @@ } }, "urql.js": { - "bundled": 4312, - "minified": 2311, - "gzipped": 852, + "bundled": 4539, + "minified": 2369, + "gzipped": 856, "treeshaked": { "rollup": { - "code": 199, + "code": 170, "import_statements": 85 }, "webpack": { - "code": 1387 + "code": 1355 } } } diff --git a/src/query.ts b/src/query.ts index 5e1b5a76ac..46915d32f8 100644 --- a/src/query.ts +++ b/src/query.ts @@ -1,4 +1,4 @@ -export { queryClientAtom, getQueryClientAtom } from './query/queryClientAtom' +export { queryClientAtom } from './query/queryClientAtom' export { atomWithQuery } from './query/atomWithQuery' export { atomWithInfiniteQuery } from './query/atomWithInfiniteQuery' export type { diff --git a/src/query/atomWithInfiniteQuery.ts b/src/query/atomWithInfiniteQuery.ts index 987580a17b..5569228d88 100644 --- a/src/query/atomWithInfiniteQuery.ts +++ b/src/query/atomWithInfiniteQuery.ts @@ -1,4 +1,5 @@ import { + QueryClient, QueryKey, InfiniteQueryObserver, InfiniteQueryObserverOptions, @@ -9,7 +10,7 @@ import { } from 'react-query' import { atom } from 'jotai' import type { WritableAtom, Getter } from 'jotai' -import { getQueryClientAtom } from './queryClientAtom' +import { queryClientAtom } from './queryClientAtom' export type AtomWithInfiniteQueryAction = { type: 'refetch' | 'fetchNextPage' | 'fetchPreviousPage' @@ -39,11 +40,12 @@ export function atomWithInfiniteQuery< TError, TData, TQueryData - >) + >), + getQueryClient: (get: Getter) => QueryClient = (get) => get(queryClientAtom) ): WritableAtom, AtomWithInfiniteQueryAction> { const queryDataAtom = atom( (get) => { - const queryClient = get(getQueryClientAtom) + const queryClient = getQueryClient(get) const options = typeof createQuery === 'function' ? createQuery(get) : createQuery let settlePromise: @@ -75,6 +77,7 @@ export function atomWithInfiniteQuery< } }) ) + dataAtom.scope = queryAtom.scope let setData: ( data: InfiniteData | Promise> ) => void = () => { @@ -128,6 +131,7 @@ export function atomWithInfiniteQuery< return { dataAtom, observer, options } }, (get, _set, action: AtomWithInfiniteQueryAction) => { + queryDataAtom.scope = queryAtom.scope const { observer } = get(queryDataAtom) switch (action.type) { case 'refetch': { @@ -151,10 +155,14 @@ export function atomWithInfiniteQuery< AtomWithInfiniteQueryAction >( (get) => { + queryDataAtom.scope = queryAtom.scope const { dataAtom } = get(queryDataAtom) return get(dataAtom) }, - (_get, set, action) => set(queryDataAtom, action) // delegate action + (_get, set, action) => { + queryDataAtom.scope = queryAtom.scope + set(queryDataAtom, action) // delegate action + } ) return queryAtom } diff --git a/src/query/atomWithQuery.ts b/src/query/atomWithQuery.ts index 80da7fc390..b5c00742ca 100644 --- a/src/query/atomWithQuery.ts +++ b/src/query/atomWithQuery.ts @@ -1,4 +1,5 @@ import { + QueryClient, QueryKey, QueryObserver, QueryObserverOptions, @@ -7,7 +8,7 @@ import { } from 'react-query' import { atom } from 'jotai' import type { WritableAtom, PrimitiveAtom, Getter } from 'jotai' -import { getQueryClientAtom } from './queryClientAtom' +import { queryClientAtom } from './queryClientAtom' export type AtomWithQueryAction = { type: 'refetch' } @@ -26,7 +27,8 @@ export function atomWithQuery< | AtomWithQueryOptions | (( get: Getter - ) => AtomWithQueryOptions) + ) => AtomWithQueryOptions), + getQueryClient: (get: Getter) => QueryClient = (get) => get(queryClientAtom) ): WritableAtom { const queryDataAtom: WritableAtom< { @@ -36,7 +38,7 @@ export function atomWithQuery< AtomWithQueryAction > = atom( (get) => { - const queryClient = get(getQueryClientAtom) + const queryClient = getQueryClient(get) const options = typeof createQuery === 'function' ? createQuery(get) : createQuery let settlePromise: ((data: TData | null, err?: TError) => void) | null = @@ -60,6 +62,7 @@ export function atomWithQuery< } }) ) + dataAtom.scope = queryAtom.scope let setData: (data: TData | Promise) => void = () => { throw new Error('atomWithQuery: setting data without mount') } @@ -108,6 +111,7 @@ export function atomWithQuery< (get, set, action: AtomWithQueryAction) => { switch (action.type) { case 'refetch': { + queryDataAtom.scope = queryAtom.scope const { dataAtom, observer } = get(queryDataAtom) set(dataAtom, new Promise(() => {})) // infinite pending const p = observer.refetch({ cancelRefetch: true }).then(() => {}) @@ -118,10 +122,14 @@ export function atomWithQuery< ) const queryAtom = atom( (get) => { + queryDataAtom.scope = queryAtom.scope const { dataAtom } = get(queryDataAtom) return get(dataAtom) }, - (_get, set, action) => set(queryDataAtom, action) // delegate action + (_get, set, action) => { + queryDataAtom.scope = queryAtom.scope + set(queryDataAtom, action) // delegate action + } ) return queryAtom } diff --git a/src/query/queryClientAtom.ts b/src/query/queryClientAtom.ts index 773c779a73..8040114f82 100644 --- a/src/query/queryClientAtom.ts +++ b/src/query/queryClientAtom.ts @@ -1,8 +1,4 @@ import { atom } from 'jotai' import { QueryClient } from 'react-query' -export const queryClientAtom = atom(null) - -export const getQueryClientAtom = atom( - (get) => get(queryClientAtom) || new QueryClient() -) +export const queryClientAtom = atom(new QueryClient()) diff --git a/src/redux/atomWithStore.ts b/src/redux/atomWithStore.ts index 2ad4398e44..98a1200f19 100644 --- a/src/redux/atomWithStore.ts +++ b/src/redux/atomWithStore.ts @@ -14,7 +14,10 @@ export function atomWithStore( return unsub } const derivedAtom = atom( - (get) => get(baseAtom), + (get) => { + baseAtom.scope = derivedAtom.scope + return get(baseAtom) + }, (_get, _set, action: A) => { store.dispatch(action) } diff --git a/src/urql/atomWithMutation.ts b/src/urql/atomWithMutation.ts index cd264ae313..31ade87055 100644 --- a/src/urql/atomWithMutation.ts +++ b/src/urql/atomWithMutation.ts @@ -6,7 +6,7 @@ import { } from '@urql/core' import { atom } from 'jotai' import type { Getter } from 'jotai' -import { getClientAtom } from './clientAtom' +import { clientAtom } from './clientAtom' type MutationAction = { variables?: Variables @@ -16,7 +16,7 @@ type MutationAction = { export function atomWithMutation( createQuery: (get: Getter) => TypedDocumentNode | string, - getClient: (get: Getter) => Client = (get) => get(getClientAtom) + getClient: (get: Getter) => Client = (get) => get(clientAtom) ) { const operationResultAtom = atom< OperationResult | Promise> @@ -24,8 +24,12 @@ export function atomWithMutation( new Promise>(() => {}) // infinite pending ) const queryResultAtom = atom( - (get) => get(operationResultAtom), + (get) => { + operationResultAtom.scope = queryResultAtom.scope + return get(operationResultAtom) + }, (get, set, action: MutationAction) => { + operationResultAtom.scope = queryResultAtom.scope set( operationResultAtom, new Promise>(() => {}) // new fetch diff --git a/src/urql/atomWithQuery.ts b/src/urql/atomWithQuery.ts index 521f51d895..1edfc0658c 100644 --- a/src/urql/atomWithQuery.ts +++ b/src/urql/atomWithQuery.ts @@ -8,7 +8,7 @@ import { } from '@urql/core' import { atom } from 'jotai' import type { Getter } from 'jotai' -import { getClientAtom } from './clientAtom' +import { clientAtom } from './clientAtom' type QueryArgs = { query: TypedDocumentNode | string @@ -19,7 +19,7 @@ type QueryArgs = { export function atomWithQuery( createQueryArgs: (get: Getter) => QueryArgs, - getClient: (get: Getter) => Client = (get) => get(getClientAtom) + getClient: (get: Getter) => Client = (get) => get(clientAtom) ) { const queryResultAtom = atom((get) => { const client = getClient(get) @@ -34,6 +34,7 @@ export function atomWithQuery( resolve = r }) ) + resultAtom.scope = queryAtom.scope let setResult: (result: OperationResult) => void = () => { throw new Error('setting result without mount') } @@ -69,6 +70,7 @@ export function atomWithQuery( return { resultAtom, args } }) const queryAtom = atom((get) => { + queryResultAtom.scope = queryAtom.scope const { resultAtom } = get(queryResultAtom) return get(resultAtom) }) diff --git a/src/urql/atomWithSubscription.ts b/src/urql/atomWithSubscription.ts index edc7a03008..df944611f1 100644 --- a/src/urql/atomWithSubscription.ts +++ b/src/urql/atomWithSubscription.ts @@ -7,7 +7,7 @@ import { } from '@urql/core' import { atom } from 'jotai' import type { Getter } from 'jotai' -import { getClientAtom } from './clientAtom' +import { clientAtom } from './clientAtom' type SubscriptionArgs = { query: TypedDocumentNode | string @@ -17,7 +17,7 @@ type SubscriptionArgs = { export function atomWithSubscription( createSubscriptionArgs: (get: Getter) => SubscriptionArgs, - getClient: (get: Getter) => Client = (get) => get(getClientAtom) + getClient: (get: Getter) => Client = (get) => get(clientAtom) ) { const queryResultAtom = atom((get) => { const client = getClient(get) @@ -32,6 +32,7 @@ export function atomWithSubscription( resolve = r }) ) + resultAtom.scope = queryAtom.scope let setResult: (result: OperationResult) => void = () => { throw new Error('setting result without mount') } @@ -68,6 +69,7 @@ export function atomWithSubscription( return { resultAtom, args } }) const queryAtom = atom((get) => { + queryResultAtom.scope = queryAtom.scope const { resultAtom } = get(queryResultAtom) return get(resultAtom) }) diff --git a/src/urql/clientAtom.ts b/src/urql/clientAtom.ts index 974fb0b278..f51b46d03c 100644 --- a/src/urql/clientAtom.ts +++ b/src/urql/clientAtom.ts @@ -1,12 +1,8 @@ import { atom } from 'jotai' -import { Client, createClient } from '@urql/core' +import { createClient } from '@urql/core' const DEFAULT_URL = (typeof process === 'object' && process.env.JOTAI_URQL_DEFAULT_URL) || '/graphql' -export const clientAtom = atom(null) - -export const getClientAtom = atom( - (get) => get(clientAtom) || createClient({ url: DEFAULT_URL }) -) +export const clientAtom = atom(createClient({ url: DEFAULT_URL })) diff --git a/src/utils/atomWithDefault.ts b/src/utils/atomWithDefault.ts index 3aff974aaf..fc8e8c922e 100644 --- a/src/utils/atomWithDefault.ts +++ b/src/utils/atomWithDefault.ts @@ -11,6 +11,7 @@ export function atomWithDefault(getDefault: Read) { const overwrittenAtom = atom(EMPTY) const anAtom: WritableAtom = atom( (get) => { + overwrittenAtom.scope = anAtom.scope const overwritten = get(overwrittenAtom) if (overwritten !== EMPTY) { return overwritten @@ -18,6 +19,7 @@ export function atomWithDefault(getDefault: Read) { return getDefault(get) }, (get, set, update) => { + overwrittenAtom.scope = anAtom.scope if (update === RESET) { set(overwrittenAtom, EMPTY) } else { diff --git a/src/utils/atomWithStorage.ts b/src/utils/atomWithStorage.ts index b7aff4b353..1539901674 100644 --- a/src/utils/atomWithStorage.ts +++ b/src/utils/atomWithStorage.ts @@ -68,8 +68,12 @@ export function atomWithStorage( } const anAtom = atom( - (get) => get(baseAtom), + (get) => { + baseAtom.scope = anAtom.scope + return get(baseAtom) + }, (get, set, update: SetStateAction) => { + baseAtom.scope = anAtom.scope const newValue = typeof update === 'function' ? (update as (prev: Value) => Value)(get(baseAtom)) diff --git a/src/utils/selectAtom.ts b/src/utils/selectAtom.ts index 2e958bf272..6e5556c931 100644 --- a/src/utils/selectAtom.ts +++ b/src/utils/selectAtom.ts @@ -15,6 +15,7 @@ export function selectAtom( return cachedAtom as Atom } const refAtom = atom(() => ({} as { prev?: Slice })) + refAtom.scope = anAtom.scope const derivedAtom = atom((get) => { const slice = selector(get(anAtom)) const ref = get(refAtom) diff --git a/src/utils/splitAtom.ts b/src/utils/splitAtom.ts index 72ede2e119..6bd6d930ff 100644 --- a/src/utils/splitAtom.ts +++ b/src/utils/splitAtom.ts @@ -46,6 +46,7 @@ export function splitAtom( keyList?: Key[] }) ) + refAtom.scope = arrAtom.scope const read = (get: Getter) => { const ref = get(refAtom) let nextAtomList: Atom[] = [] diff --git a/src/valtio/atomWithProxy.ts b/src/valtio/atomWithProxy.ts index eaa132c6f6..9d8dc60755 100644 --- a/src/valtio/atomWithProxy.ts +++ b/src/valtio/atomWithProxy.ts @@ -45,8 +45,12 @@ export function atomWithProxy(proxyObject: Value) { return unsub } const derivedAtom = atom( - (get) => get(baseAtom) as Value, + (get) => { + baseAtom.scope = derivedAtom.scope + return get(baseAtom) as Value + }, (get, _set, update: SetStateAction) => { + baseAtom.scope = derivedAtom.scope const newValue = typeof update === 'function' ? (update as (prev: Value) => Value)(get(baseAtom) as Value) diff --git a/src/xstate/atomWithMachine.ts b/src/xstate/atomWithMachine.ts index e376a7e3b4..d98e98b21f 100644 --- a/src/xstate/atomWithMachine.ts +++ b/src/xstate/atomWithMachine.ts @@ -34,6 +34,7 @@ export function atomWithMachine< ) const machineAtom = atom( (get) => { + cachedMachineAtom.scope = machineStateWithServiceAtom.scope const cachedMachine = get(cachedMachineAtom) if (cachedMachine) { return cachedMachine @@ -73,6 +74,8 @@ export function atomWithMachine< return { machine: machineWithConfig, service } }, (get, set, _arg) => { + cachedMachineAtom.scope = machineStateWithServiceAtom.scope + machineAtom.scope = machineStateWithServiceAtom.scope set(cachedMachineAtom, get(machineAtom)) } ) @@ -81,9 +84,16 @@ export function atomWithMachine< } const cachedMachineStateAtom = atom(null) const machineStateAtom = atom( - (get) => - get(cachedMachineStateAtom) ?? get(machineAtom).machine.initialState, + (get) => { + cachedMachineStateAtom.scope = machineStateWithServiceAtom.scope + machineAtom.scope = machineStateWithServiceAtom.scope + return ( + get(cachedMachineStateAtom) ?? get(machineAtom).machine.initialState + ) + }, (get, set, registerCleanup: (cleanup: () => void) => void) => { + cachedMachineStateAtom.scope = machineStateWithServiceAtom.scope + machineAtom.scope = machineStateWithServiceAtom.scope const { service } = get(machineAtom) service.onTransition((nextState) => { set(cachedMachineStateAtom, nextState) @@ -111,8 +121,12 @@ export function atomWithMachine< } } const machineStateWithServiceAtom = atom( - (get) => get(machineStateAtom), + (get) => { + machineStateAtom.scope = machineStateWithServiceAtom.scope + return get(machineStateAtom) + }, (get, _set, event: Parameters[0]) => { + machineAtom.scope = machineStateWithServiceAtom.scope const { service } = get(machineAtom) service.send(event) } diff --git a/src/zustand/atomWithStore.ts b/src/zustand/atomWithStore.ts index 344e9572cf..db7573c5c5 100644 --- a/src/zustand/atomWithStore.ts +++ b/src/zustand/atomWithStore.ts @@ -13,8 +13,12 @@ export function atomWithStore(store: StoreApi) { return unsub } const derivedAtom = atom( - (get) => get(baseAtom), + (get) => { + baseAtom.scope = derivedAtom.scope + return get(baseAtom) + }, (get, _set, update: SetStateAction) => { + baseAtom.scope = derivedAtom.scope const newState = typeof update === 'function' ? (update as (prev: T) => T)(get(baseAtom))