Remove Derivation.changesWithoutValues()

And replace it with `Derivation.onStale()`
This commit is contained in:
Aria Minaei 2022-12-01 13:31:16 +01:00
parent 9094e3041e
commit 5c1aa1cd50
13 changed files with 19 additions and 916 deletions

View file

@ -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).

View file

@ -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
}

View file

@ -17,7 +17,7 @@ export default function* iterateAndCountTicks<V>(
}
let ticksCountedSinceLastYield = 0
const untap = d.changesWithoutValues().tap(() => {
const untap = d.onStale(() => {
ticksCountedSinceLastYield++
})

View file

@ -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)
}

View file

@ -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(() => {})
}
/**