Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
dai-shi committed Oct 6, 2023
1 parent 3533652 commit f95519f
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 51 deletions.
69 changes: 22 additions & 47 deletions src/mutableAtom/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,31 +30,28 @@ export function makeMutableAtom<Value>(

const storeAtom = atom<
Store<Value>,
[ActionWithPayload<'setValueAsync', Value> | Action<'mount'>],
void
[ActionWithPayload<'setValue', Value> | Action<'getValue'>],
void | Value
>(
(get, { setSelf }) => ({
proxyState: null,
getValue: () => get(valueAtom).value,
setValue: async (value: Value) => {
await defer()
setSelf({ type: 'setValueAsync', payload: value })
},
}),
(_get, { setSelf }) => {
const getValue = () => setSelf({ type: 'getValue' }) as Value
const store: Store<Value> = {
proxyState: createProxyState(getValue(), () => store),
getValue,
setValue: (value: Value) =>
setSelf({ type: 'setValue', payload: value }) as void,
}
return store
},
(get, set, action) => {
if (action.type === 'setValueAsync') {
if (action.type === 'setValue') {
set(valueAtom, { value: action.payload })
} else if (action.type === 'mount') {
const store = get(storeAtom)
store.setValue = (value: Value) => {
set(valueAtom, { value })
}
} else if (action.type === 'getValue') {
return get(valueAtom).value
}
}
)

storeAtom.onMount = (setAtom) => setAtom({ type: 'mount' })

if (process.env.NODE_ENV !== 'production') {
storeAtom.debugPrivate = true
}
Expand All @@ -65,9 +62,8 @@ export function makeMutableAtom<Value>(
function onChange(getStore: () => Store<Value>) {
return () => {
const { proxyState, getValue, setValue } = getStore()
if (proxyState === null) return
const { value } = snapshot(proxyState)
if (value !== getValue()) {
if (!Object.is(value, getValue())) {
setValue(value as Awaited<Value>)
}
}
Expand All @@ -76,23 +72,10 @@ export function makeMutableAtom<Value>(
/**
* create the proxy state and subscribe to it
*/
function createProxyState(getStore: () => Store<Value>) {
const store = getStore()
const value = store.getValue()
store.proxyState ??= proxyFn({ value })
store.proxyState.value = value
subscribe(store.proxyState, onChange(getStore), true)
return store.proxyState
}

/**
* return the proxy if it exists, otherwise create and subscribe to it
*/
function ensureProxyState(getStore: () => Store<Value>) {
const { proxyState } = getStore()
if (proxyState === null) {
return createProxyState(getStore)
}
function createProxyState(initialValue: Value, getStore: () => Store<Value>) {
const proxyState = proxyFn({ value: initialValue })
proxyState.value = initialValue
subscribe(proxyState, onChange(getStore), true)
return proxyState
}

Expand All @@ -119,20 +102,12 @@ export function makeMutableAtom<Value>(
*/
const proxyEffectAtom = atom<ProxyState<Value>>((get) => {
get(valueAtom) // subscribe to value updates
const getStore = () => get(storeAtom)
const proxyState = ensureProxyState(getStore)
return wrapProxyState(proxyState)
const store = get(storeAtom)
return wrapProxyState(store.proxyState)
})
return proxyEffectAtom
}

const defaultOptions = {
proxyFn: proxy,
}

/**
* delays execution until next microtask
*/
function defer() {
return Promise.resolve().then()
}
6 changes: 2 additions & 4 deletions src/mutableAtom/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ export type Wrapped<T> = { value: T }

type ProxyFn<T> = (obj: Wrapped<T>) => Wrapped<T>

type PromiseOrValue<T> = Promise<T> | T

export type Store<Value> = {
proxyState: ProxyState<Value> | null
proxyState: ProxyState<Value>
getValue: () => Value
setValue: (value: Value) => PromiseOrValue<void>
setValue: (value: Value) => void
}

export type Options<T> = {
Expand Down

0 comments on commit f95519f

Please sign in to comment.