Remove Derivation.changesWithoutValues()
And replace it with `Derivation.onStale()`
This commit is contained in:
parent
9094e3041e
commit
5c1aa1cd50
13 changed files with 19 additions and 916 deletions
|
@ -23,13 +23,7 @@ export interface IDerivation<V> {
|
|||
*/
|
||||
changes(ticker: Ticker): Tappable<V>
|
||||
|
||||
/**
|
||||
* Like {@link changes} but with a different performance model. `changesWithoutValues` returns a {@link Tappable} that
|
||||
* updates every time the derivation is updated, even if the value didn't change, and the callback is called without
|
||||
* the value. The advantage of this is that you have control over when the derivation is freshened, it won't
|
||||
* automatically be kept fresh.
|
||||
*/
|
||||
changesWithoutValues(): Tappable<void>
|
||||
onStale(cb: () => void): VoidFn
|
||||
|
||||
/**
|
||||
* Keep the derivation hot, even if there are no tappers (subscribers).
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
import type {$FixMe} from '../types'
|
||||
import AbstractDerivation from './AbstractDerivation'
|
||||
import type {IDerivation} from './IDerivation'
|
||||
import {isDerivation} from './IDerivation'
|
||||
|
||||
enum UPDATE_NEEDED_FROM {
|
||||
none = 0,
|
||||
dep = 1,
|
||||
inner = 2,
|
||||
}
|
||||
|
||||
const makeFlatMapDerivationClass = () => {
|
||||
// TODO once prism and AbstractDerivation are merged into one, we should delete this file
|
||||
class FlatMapDerivation<V, DepType> extends AbstractDerivation<V> {
|
||||
private _innerDerivation: undefined | null | IDerivation<V>
|
||||
private _staleDependency: UPDATE_NEEDED_FROM
|
||||
|
||||
static displayName = 'flatMap'
|
||||
|
||||
constructor(
|
||||
readonly _depDerivation: IDerivation<DepType>,
|
||||
readonly _fn: (v: DepType) => IDerivation<V> | V,
|
||||
) {
|
||||
super()
|
||||
this._innerDerivation = undefined
|
||||
this._staleDependency = UPDATE_NEEDED_FROM.dep
|
||||
|
||||
this._addDependency(_depDerivation)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
_recalculateHot() {
|
||||
const updateNeededFrom = this._staleDependency
|
||||
this._staleDependency = UPDATE_NEEDED_FROM.none
|
||||
|
||||
if (updateNeededFrom === UPDATE_NEEDED_FROM.inner) {
|
||||
// @ts-ignore
|
||||
return this._innerDerivation.getValue()
|
||||
}
|
||||
|
||||
const possibleInnerDerivation = this._fn(this._depDerivation.getValue())
|
||||
|
||||
if (isDerivation(possibleInnerDerivation)) {
|
||||
this._innerDerivation = possibleInnerDerivation
|
||||
this._addDependency(possibleInnerDerivation)
|
||||
return possibleInnerDerivation.getValue()
|
||||
} else {
|
||||
return possibleInnerDerivation
|
||||
}
|
||||
}
|
||||
|
||||
protected _recalculateCold() {
|
||||
const possibleInnerDerivation = this._fn(this._depDerivation.getValue())
|
||||
|
||||
if (isDerivation(possibleInnerDerivation)) {
|
||||
return possibleInnerDerivation.getValue()
|
||||
} else {
|
||||
return possibleInnerDerivation
|
||||
}
|
||||
}
|
||||
|
||||
protected _recalculate() {
|
||||
return this.isHot ? this._recalculateHot() : this._recalculateCold()
|
||||
}
|
||||
|
||||
protected _reactToDependencyBecomingStale(
|
||||
msgComingFrom: IDerivation<unknown>,
|
||||
) {
|
||||
const updateNeededFrom =
|
||||
msgComingFrom === this._depDerivation
|
||||
? UPDATE_NEEDED_FROM.dep
|
||||
: UPDATE_NEEDED_FROM.inner
|
||||
|
||||
if (
|
||||
updateNeededFrom === UPDATE_NEEDED_FROM.inner &&
|
||||
msgComingFrom !== this._innerDerivation
|
||||
) {
|
||||
throw Error(
|
||||
`got a _reactToDependencyBecomingStale() from neither the dep nor the inner derivation`,
|
||||
)
|
||||
}
|
||||
|
||||
if (this._staleDependency === UPDATE_NEEDED_FROM.none) {
|
||||
this._staleDependency = updateNeededFrom
|
||||
|
||||
if (updateNeededFrom === UPDATE_NEEDED_FROM.dep) {
|
||||
this._removeInnerDerivation()
|
||||
}
|
||||
} else if (this._staleDependency === UPDATE_NEEDED_FROM.dep) {
|
||||
} else {
|
||||
if (updateNeededFrom === UPDATE_NEEDED_FROM.dep) {
|
||||
this._staleDependency = UPDATE_NEEDED_FROM.dep
|
||||
this._removeInnerDerivation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _removeInnerDerivation() {
|
||||
if (this._innerDerivation) {
|
||||
this._removeDependency(this._innerDerivation)
|
||||
this._innerDerivation = undefined
|
||||
}
|
||||
}
|
||||
|
||||
protected _keepHot() {
|
||||
this._staleDependency = UPDATE_NEEDED_FROM.dep
|
||||
this.getValue()
|
||||
}
|
||||
|
||||
protected _becomeCold() {
|
||||
this._staleDependency = UPDATE_NEEDED_FROM.dep
|
||||
this._removeInnerDerivation()
|
||||
}
|
||||
}
|
||||
return FlatMapDerivation
|
||||
}
|
||||
|
||||
let cls: ReturnType<typeof makeFlatMapDerivationClass> | undefined = undefined
|
||||
|
||||
export default function flatMap<V, R>(
|
||||
dep: IDerivation<V>,
|
||||
fn: (v: V) => R,
|
||||
): IDerivation<R extends IDerivation<infer T> ? T : R> {
|
||||
if (!cls) {
|
||||
cls = makeFlatMapDerivationClass()
|
||||
}
|
||||
return new cls(dep, fn) as $FixMe
|
||||
}
|
|
@ -17,7 +17,7 @@ export default function* iterateAndCountTicks<V>(
|
|||
}
|
||||
|
||||
let ticksCountedSinceLastYield = 0
|
||||
const untap = d.changesWithoutValues().tap(() => {
|
||||
const untap = d.onStale(() => {
|
||||
ticksCountedSinceLastYield++
|
||||
})
|
||||
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
import AbstractDerivation from './AbstractDerivation'
|
||||
import type {IDerivation} from './IDerivation'
|
||||
|
||||
// Exporting from a function because of the circular dependency with AbstractDerivation
|
||||
const makeMapDerivationClass = () =>
|
||||
// TODO once prism and AbstractDerivation are merged into one, we should delete this file
|
||||
class MapDerivation<T, V> extends AbstractDerivation<V> {
|
||||
constructor(
|
||||
private readonly _dep: IDerivation<T>,
|
||||
private readonly _fn: (t: T) => V,
|
||||
) {
|
||||
super()
|
||||
this._addDependency(_dep)
|
||||
}
|
||||
|
||||
_recalculate() {
|
||||
return this._fn(this._dep.getValue())
|
||||
}
|
||||
|
||||
_reactToDependencyBecomingStale() {}
|
||||
}
|
||||
|
||||
let cls: ReturnType<typeof makeMapDerivationClass> | undefined = undefined
|
||||
|
||||
export default function map<V, R>(
|
||||
dep: IDerivation<V>,
|
||||
fn: (v: V) => R,
|
||||
): IDerivation<R> {
|
||||
if (!cls) {
|
||||
cls = makeMapDerivationClass()
|
||||
}
|
||||
return new cls(dep, fn)
|
||||
}
|
|
@ -231,25 +231,18 @@ class PrismDerivation<V> implements IDerivation<V> {
|
|||
return new DerivationEmitter(this, ticker).tappable()
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This is renamed to {@link PrismDerivation.onStale}.
|
||||
*/
|
||||
changesWithoutValues(): Tappable<void> {
|
||||
return this.onStale()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a tappable that fires every time the prism's state goes from `fresh-\>stale.`
|
||||
*/
|
||||
onStale(): Tappable<void> {
|
||||
return new DerivationValuelessEmitter(this).tappable()
|
||||
onStale(callback: () => void): VoidFn {
|
||||
return new DerivationValuelessEmitter(this).tappable().tap(callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep the derivation hot, even if there are no tappers (subscribers).
|
||||
*/
|
||||
keepHot() {
|
||||
return this.onStale().tap(() => {})
|
||||
return this.onStale(() => {})
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue