Retire DerivationFromSource
(1/2)
This is supposed to break the build. In the next commit, I'll implement `HotScope.source()` to fix the build.
This commit is contained in:
parent
918dd754a7
commit
b117ee0aff
5 changed files with 66 additions and 103 deletions
|
@ -1,7 +1,6 @@
|
|||
import get from 'lodash-es/get'
|
||||
import isPlainObject from 'lodash-es/isPlainObject'
|
||||
import last from 'lodash-es/last'
|
||||
import DerivationFromSource from './derivations/DerivationFromSource'
|
||||
import type {IDerivation} from './derivations/IDerivation'
|
||||
import {isDerivation} from './derivations/IDerivation'
|
||||
import type {Pointer, PointerType} from './pointer'
|
||||
|
@ -10,6 +9,7 @@ import pointer, {getPointerMeta} from './pointer'
|
|||
import type {$FixMe, $IntentionalAny} from './types'
|
||||
import type {PathBasedReducer} from './utils/PathBasedReducer'
|
||||
import updateDeep from './utils/updateDeep'
|
||||
import prism from './derivations/prism/prism'
|
||||
|
||||
type Listener = (newVal: unknown) => void
|
||||
|
||||
|
@ -247,10 +247,14 @@ export default class Atom<State extends {}>
|
|||
* @param path - The path to create the derivation at.
|
||||
*/
|
||||
getIdentityDerivation(path: Array<string | number>): IDerivation<unknown> {
|
||||
return new DerivationFromSource<$IntentionalAny>(
|
||||
(listener) => this._onPathValueChange(path, listener),
|
||||
() => this.getIn(path),
|
||||
)
|
||||
const subscribe = (listener: (val: unknown) => void) =>
|
||||
this._onPathValueChange(path, listener)
|
||||
|
||||
const getValue = () => this.getIn(path)
|
||||
|
||||
return prism(() => {
|
||||
return prism.source('value', subscribe, getValue)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import DerivationFromSource from './derivations/DerivationFromSource'
|
||||
import type {IDerivation} from './derivations/IDerivation'
|
||||
import prism from './derivations/prism/prism'
|
||||
import Emitter from './utils/Emitter'
|
||||
|
||||
/**
|
||||
|
@ -51,10 +51,12 @@ export default class Box<V> implements IBox<V> {
|
|||
*/
|
||||
protected _value: V,
|
||||
) {
|
||||
this._publicDerivation = new DerivationFromSource(
|
||||
(listener) => this._emitter.tappable.tap(listener),
|
||||
this.get.bind(this),
|
||||
)
|
||||
const subscribe = (listener: (val: V) => void) =>
|
||||
this._emitter.tappable.tap(listener)
|
||||
const getValue = () => this._value
|
||||
this._publicDerivation = prism(() => {
|
||||
return prism.source('value', subscribe, getValue)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
import type {VoidFn} from '../types'
|
||||
import AbstractDerivation from './AbstractDerivation'
|
||||
|
||||
const noop = () => {}
|
||||
|
||||
/**
|
||||
* Represents a derivation based on a tappable (subscribable) data source.
|
||||
*/
|
||||
export default class DerivationFromSource<V> extends AbstractDerivation<V> {
|
||||
private _untapFromChanges: () => void
|
||||
private _cachedValue: undefined | V
|
||||
private _hasCachedValue: boolean
|
||||
|
||||
/**
|
||||
* @param _tapToSource - A function that takes a listener and subscribes it to the underlying data source.
|
||||
* @param _getValueFromSource - A function that returns the current value of the data source.
|
||||
*/
|
||||
constructor(
|
||||
private readonly _tapToSource: (listener: (newValue: V) => void) => VoidFn,
|
||||
private readonly _getValueFromSource: () => V,
|
||||
) {
|
||||
super()
|
||||
this._untapFromChanges = noop
|
||||
this._cachedValue = undefined
|
||||
this._hasCachedValue = false
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_recalculate() {
|
||||
if (this.isHot) {
|
||||
if (!this._hasCachedValue) {
|
||||
this._cachedValue = this._getValueFromSource()
|
||||
this._hasCachedValue = true
|
||||
}
|
||||
return this._cachedValue as V
|
||||
} else {
|
||||
return this._getValueFromSource()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_keepHot() {
|
||||
this._hasCachedValue = false
|
||||
this._cachedValue = undefined
|
||||
|
||||
this._untapFromChanges = this._tapToSource((newValue) => {
|
||||
this._hasCachedValue = true
|
||||
this._cachedValue = newValue
|
||||
this._markAsStale(this)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_becomeCold() {
|
||||
this._untapFromChanges()
|
||||
this._untapFromChanges = noop
|
||||
|
||||
this._hasCachedValue = false
|
||||
this._cachedValue = undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_reactToDependencyBecomingStale() {}
|
||||
}
|
|
@ -28,7 +28,6 @@ class HotHandle<V> {
|
|||
this._dependents.delete(d)
|
||||
}
|
||||
addDependent(d: IDependent) {
|
||||
// having no dependents means the prism is currently cold
|
||||
this._dependents.add(d)
|
||||
}
|
||||
private _didMarkDependentsAsStale: boolean = false
|
||||
|
@ -328,7 +327,7 @@ class PrismDerivation<V> implements IDerivation<V> {
|
|||
if (state.hot) {
|
||||
val = state.handle.getValue()
|
||||
} else {
|
||||
val = ColdStuff.calculateColdPrism(this._fn)
|
||||
val = calculateColdPrism(this._fn)
|
||||
}
|
||||
|
||||
reportResolutionEnd(this)
|
||||
|
@ -383,6 +382,11 @@ interface PrismScope {
|
|||
state<T>(key: string, initialValue: T): [T, (val: T) => void]
|
||||
ref<T>(key: string, initialValue: T): IRef<T>
|
||||
sub(key: string): PrismScope
|
||||
source<V>(
|
||||
key: string,
|
||||
subscribe: (fn: (val: V) => void) => VoidFn,
|
||||
getValue: () => V,
|
||||
): V
|
||||
}
|
||||
|
||||
class HotScope implements PrismScope {
|
||||
|
@ -482,6 +486,12 @@ class HotScope implements PrismScope {
|
|||
}
|
||||
this.effects.clear()
|
||||
}
|
||||
|
||||
source<V>(
|
||||
key: string,
|
||||
subscribe: (fn: (val: V) => void) => VoidFn,
|
||||
getValue: () => V,
|
||||
): V {}
|
||||
}
|
||||
|
||||
function cleanupScopeStack(scope: HotScope) {
|
||||
|
@ -694,6 +704,19 @@ const possibleDerivationToValue = <
|
|||
}
|
||||
}
|
||||
|
||||
function source<V>(
|
||||
key: string,
|
||||
subscribe: (fn: (val: V) => void) => VoidFn,
|
||||
getValue: () => V,
|
||||
): V {
|
||||
const scope = hookScopeStack.peek()
|
||||
if (!scope) {
|
||||
throw new Error(`prism.source() is called outside of a prism() call.`)
|
||||
}
|
||||
|
||||
return scope.source(key, subscribe, getValue)
|
||||
}
|
||||
|
||||
type IPrismFn = {
|
||||
<T>(fn: () => T): IDerivation<T>
|
||||
ref: typeof ref
|
||||
|
@ -704,6 +727,7 @@ type IPrismFn = {
|
|||
scope: typeof scope
|
||||
sub: typeof sub
|
||||
inPrism: typeof inPrism
|
||||
source: typeof source
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -736,28 +760,33 @@ class ColdScope implements PrismScope {
|
|||
sub(key: string): ColdScope {
|
||||
return new ColdScope()
|
||||
}
|
||||
source<V>(
|
||||
key: string,
|
||||
subscribe: (fn: (val: V) => void) => VoidFn,
|
||||
getValue: () => V,
|
||||
): V {
|
||||
return getValue()
|
||||
}
|
||||
}
|
||||
|
||||
namespace ColdStuff {
|
||||
export function calculateColdPrism<V>(fn: () => V): V {
|
||||
const scope = new ColdScope()
|
||||
hookScopeStack.push(scope)
|
||||
let value: V
|
||||
try {
|
||||
value = fn()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
const topOfTheStack = hookScopeStack.pop()
|
||||
if (topOfTheStack !== scope) {
|
||||
console.warn(
|
||||
// @todo guide the user to report the bug in an issue
|
||||
`The Prism hook stack has slipped. This is a bug.`,
|
||||
)
|
||||
}
|
||||
function calculateColdPrism<V>(fn: () => V): V {
|
||||
const scope = new ColdScope()
|
||||
hookScopeStack.push(scope)
|
||||
let value: V
|
||||
try {
|
||||
value = fn()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
const topOfTheStack = hookScopeStack.pop()
|
||||
if (topOfTheStack !== scope) {
|
||||
console.warn(
|
||||
// @todo guide the user to report the bug in an issue
|
||||
`The Prism hook stack has slipped. This is a bug.`,
|
||||
)
|
||||
}
|
||||
return value!
|
||||
}
|
||||
return value!
|
||||
}
|
||||
|
||||
prism.ref = ref
|
||||
|
@ -768,5 +797,6 @@ prism.state = state
|
|||
prism.scope = scope
|
||||
prism.sub = sub
|
||||
prism.inPrism = inPrism
|
||||
prism.source = source
|
||||
|
||||
export default prism
|
||||
|
|
|
@ -9,7 +9,6 @@ export {default as Atom, val, valueDerivation} from './Atom'
|
|||
export {default as Box} from './Box'
|
||||
export type {IBox} from './Box'
|
||||
export {default as AbstractDerivation} from './derivations/AbstractDerivation'
|
||||
export {default as DerivationFromSource} from './derivations/DerivationFromSource'
|
||||
export {isDerivation} from './derivations/IDerivation'
|
||||
export type {IDerivation} from './derivations/IDerivation'
|
||||
export {default as iterateAndCountTicks} from './derivations/iterateAndCountTicks'
|
||||
|
|
Loading…
Reference in a new issue