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 get from 'lodash-es/get'
|
||||||
import isPlainObject from 'lodash-es/isPlainObject'
|
import isPlainObject from 'lodash-es/isPlainObject'
|
||||||
import last from 'lodash-es/last'
|
import last from 'lodash-es/last'
|
||||||
import DerivationFromSource from './derivations/DerivationFromSource'
|
|
||||||
import type {IDerivation} from './derivations/IDerivation'
|
import type {IDerivation} from './derivations/IDerivation'
|
||||||
import {isDerivation} from './derivations/IDerivation'
|
import {isDerivation} from './derivations/IDerivation'
|
||||||
import type {Pointer, PointerType} from './pointer'
|
import type {Pointer, PointerType} from './pointer'
|
||||||
|
@ -10,6 +9,7 @@ import pointer, {getPointerMeta} from './pointer'
|
||||||
import type {$FixMe, $IntentionalAny} from './types'
|
import type {$FixMe, $IntentionalAny} from './types'
|
||||||
import type {PathBasedReducer} from './utils/PathBasedReducer'
|
import type {PathBasedReducer} from './utils/PathBasedReducer'
|
||||||
import updateDeep from './utils/updateDeep'
|
import updateDeep from './utils/updateDeep'
|
||||||
|
import prism from './derivations/prism/prism'
|
||||||
|
|
||||||
type Listener = (newVal: unknown) => void
|
type Listener = (newVal: unknown) => void
|
||||||
|
|
||||||
|
@ -247,10 +247,14 @@ export default class Atom<State extends {}>
|
||||||
* @param path - The path to create the derivation at.
|
* @param path - The path to create the derivation at.
|
||||||
*/
|
*/
|
||||||
getIdentityDerivation(path: Array<string | number>): IDerivation<unknown> {
|
getIdentityDerivation(path: Array<string | number>): IDerivation<unknown> {
|
||||||
return new DerivationFromSource<$IntentionalAny>(
|
const subscribe = (listener: (val: unknown) => void) =>
|
||||||
(listener) => this._onPathValueChange(path, listener),
|
this._onPathValueChange(path, listener)
|
||||||
() => this.getIn(path),
|
|
||||||
)
|
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 type {IDerivation} from './derivations/IDerivation'
|
||||||
|
import prism from './derivations/prism/prism'
|
||||||
import Emitter from './utils/Emitter'
|
import Emitter from './utils/Emitter'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,10 +51,12 @@ export default class Box<V> implements IBox<V> {
|
||||||
*/
|
*/
|
||||||
protected _value: V,
|
protected _value: V,
|
||||||
) {
|
) {
|
||||||
this._publicDerivation = new DerivationFromSource(
|
const subscribe = (listener: (val: V) => void) =>
|
||||||
(listener) => this._emitter.tappable.tap(listener),
|
this._emitter.tappable.tap(listener)
|
||||||
this.get.bind(this),
|
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)
|
this._dependents.delete(d)
|
||||||
}
|
}
|
||||||
addDependent(d: IDependent) {
|
addDependent(d: IDependent) {
|
||||||
// having no dependents means the prism is currently cold
|
|
||||||
this._dependents.add(d)
|
this._dependents.add(d)
|
||||||
}
|
}
|
||||||
private _didMarkDependentsAsStale: boolean = false
|
private _didMarkDependentsAsStale: boolean = false
|
||||||
|
@ -328,7 +327,7 @@ class PrismDerivation<V> implements IDerivation<V> {
|
||||||
if (state.hot) {
|
if (state.hot) {
|
||||||
val = state.handle.getValue()
|
val = state.handle.getValue()
|
||||||
} else {
|
} else {
|
||||||
val = ColdStuff.calculateColdPrism(this._fn)
|
val = calculateColdPrism(this._fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
reportResolutionEnd(this)
|
reportResolutionEnd(this)
|
||||||
|
@ -383,6 +382,11 @@ interface PrismScope {
|
||||||
state<T>(key: string, initialValue: T): [T, (val: T) => void]
|
state<T>(key: string, initialValue: T): [T, (val: T) => void]
|
||||||
ref<T>(key: string, initialValue: T): IRef<T>
|
ref<T>(key: string, initialValue: T): IRef<T>
|
||||||
sub(key: string): PrismScope
|
sub(key: string): PrismScope
|
||||||
|
source<V>(
|
||||||
|
key: string,
|
||||||
|
subscribe: (fn: (val: V) => void) => VoidFn,
|
||||||
|
getValue: () => V,
|
||||||
|
): V
|
||||||
}
|
}
|
||||||
|
|
||||||
class HotScope implements PrismScope {
|
class HotScope implements PrismScope {
|
||||||
|
@ -482,6 +486,12 @@ class HotScope implements PrismScope {
|
||||||
}
|
}
|
||||||
this.effects.clear()
|
this.effects.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
source<V>(
|
||||||
|
key: string,
|
||||||
|
subscribe: (fn: (val: V) => void) => VoidFn,
|
||||||
|
getValue: () => V,
|
||||||
|
): V {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanupScopeStack(scope: HotScope) {
|
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 = {
|
type IPrismFn = {
|
||||||
<T>(fn: () => T): IDerivation<T>
|
<T>(fn: () => T): IDerivation<T>
|
||||||
ref: typeof ref
|
ref: typeof ref
|
||||||
|
@ -704,6 +727,7 @@ type IPrismFn = {
|
||||||
scope: typeof scope
|
scope: typeof scope
|
||||||
sub: typeof sub
|
sub: typeof sub
|
||||||
inPrism: typeof inPrism
|
inPrism: typeof inPrism
|
||||||
|
source: typeof source
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -736,28 +760,33 @@ class ColdScope implements PrismScope {
|
||||||
sub(key: string): ColdScope {
|
sub(key: string): ColdScope {
|
||||||
return new ColdScope()
|
return new ColdScope()
|
||||||
}
|
}
|
||||||
|
source<V>(
|
||||||
|
key: string,
|
||||||
|
subscribe: (fn: (val: V) => void) => VoidFn,
|
||||||
|
getValue: () => V,
|
||||||
|
): V {
|
||||||
|
return getValue()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ColdStuff {
|
function calculateColdPrism<V>(fn: () => V): V {
|
||||||
export function calculateColdPrism<V>(fn: () => V): V {
|
const scope = new ColdScope()
|
||||||
const scope = new ColdScope()
|
hookScopeStack.push(scope)
|
||||||
hookScopeStack.push(scope)
|
let value: V
|
||||||
let value: V
|
try {
|
||||||
try {
|
value = fn()
|
||||||
value = fn()
|
} catch (error) {
|
||||||
} catch (error) {
|
console.error(error)
|
||||||
console.error(error)
|
} finally {
|
||||||
} finally {
|
const topOfTheStack = hookScopeStack.pop()
|
||||||
const topOfTheStack = hookScopeStack.pop()
|
if (topOfTheStack !== scope) {
|
||||||
if (topOfTheStack !== scope) {
|
console.warn(
|
||||||
console.warn(
|
// @todo guide the user to report the bug in an issue
|
||||||
// @todo guide the user to report the bug in an issue
|
`The Prism hook stack has slipped. This is a bug.`,
|
||||||
`The Prism hook stack has slipped. This is a bug.`,
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return value!
|
|
||||||
}
|
}
|
||||||
|
return value!
|
||||||
}
|
}
|
||||||
|
|
||||||
prism.ref = ref
|
prism.ref = ref
|
||||||
|
@ -768,5 +797,6 @@ prism.state = state
|
||||||
prism.scope = scope
|
prism.scope = scope
|
||||||
prism.sub = sub
|
prism.sub = sub
|
||||||
prism.inPrism = inPrism
|
prism.inPrism = inPrism
|
||||||
|
prism.source = source
|
||||||
|
|
||||||
export default prism
|
export default prism
|
||||||
|
|
|
@ -9,7 +9,6 @@ export {default as Atom, val, valueDerivation} from './Atom'
|
||||||
export {default as Box} from './Box'
|
export {default as Box} from './Box'
|
||||||
export type {IBox} from './Box'
|
export type {IBox} from './Box'
|
||||||
export {default as AbstractDerivation} from './derivations/AbstractDerivation'
|
export {default as AbstractDerivation} from './derivations/AbstractDerivation'
|
||||||
export {default as DerivationFromSource} from './derivations/DerivationFromSource'
|
|
||||||
export {isDerivation} from './derivations/IDerivation'
|
export {isDerivation} from './derivations/IDerivation'
|
||||||
export type {IDerivation} from './derivations/IDerivation'
|
export type {IDerivation} from './derivations/IDerivation'
|
||||||
export {default as iterateAndCountTicks} from './derivations/iterateAndCountTicks'
|
export {default as iterateAndCountTicks} from './derivations/iterateAndCountTicks'
|
||||||
|
|
Loading…
Reference in a new issue