theatre/packages/dataverse/src/derivations/DerivationFromSource.ts
2022-02-23 22:53:39 +01:00

72 lines
1.7 KiB
TypeScript

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() {}
}