Simplify Derivation.onChange()
It no longer uses `DerivationEmitter`.
This commit is contained in:
parent
a24a149a52
commit
194de8d833
3 changed files with 27 additions and 71 deletions
|
@ -1,64 +0,0 @@
|
||||||
import type Ticker from '../Ticker'
|
|
||||||
import Emitter from '../utils/Emitter'
|
|
||||||
import type {default as Tappable} from '../utils/Tappable'
|
|
||||||
import type {IDerivation} from './IDerivation'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An event emitter that emits events on changes to a derivation.
|
|
||||||
*/
|
|
||||||
export default class DerivationEmitter<V> {
|
|
||||||
private _derivation: IDerivation<V>
|
|
||||||
private _ticker: Ticker
|
|
||||||
private _emitter: Emitter<V>
|
|
||||||
private _lastValue: undefined | V
|
|
||||||
private _lastValueRecorded: boolean
|
|
||||||
private _hadTappers: boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param derivation - The derivation to emit events for.
|
|
||||||
* @param ticker - The ticker to use to batch events.
|
|
||||||
*/
|
|
||||||
constructor(derivation: IDerivation<V>, ticker: Ticker) {
|
|
||||||
this._derivation = derivation
|
|
||||||
this._ticker = ticker
|
|
||||||
this._emitter = new Emitter()
|
|
||||||
this._emitter.onNumberOfTappersChange(() => {
|
|
||||||
this._reactToNumberOfTappersChange()
|
|
||||||
})
|
|
||||||
this._hadTappers = false
|
|
||||||
this._lastValueRecorded = false
|
|
||||||
this._lastValue = undefined
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
private _possiblyMarkAsStale = () => {
|
|
||||||
this._ticker.onThisOrNextTick(this._refresh)
|
|
||||||
}
|
|
||||||
|
|
||||||
private _reactToNumberOfTappersChange() {
|
|
||||||
const hasTappers = this._emitter.hasTappers()
|
|
||||||
if (hasTappers !== this._hadTappers) {
|
|
||||||
this._hadTappers = hasTappers
|
|
||||||
if (hasTappers) {
|
|
||||||
this._derivation.addDependent(this._possiblyMarkAsStale)
|
|
||||||
} else {
|
|
||||||
this._derivation.removeDependent(this._possiblyMarkAsStale)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The tappable associated with the emitter. You can use it to tap (subscribe to) the underlying derivation.
|
|
||||||
*/
|
|
||||||
tappable(): Tappable<V> {
|
|
||||||
return this._emitter.tappable
|
|
||||||
}
|
|
||||||
|
|
||||||
private _refresh = () => {
|
|
||||||
const newValue = this._derivation.getValue()
|
|
||||||
if (newValue === this._lastValue && this._lastValueRecorded === true) return
|
|
||||||
this._lastValue = newValue
|
|
||||||
this._lastValueRecorded = true
|
|
||||||
this._emitter.emit(newValue)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
import type Ticker from '../../Ticker'
|
import type Ticker from '../../Ticker'
|
||||||
import type {$IntentionalAny, VoidFn} from '../../types'
|
import type {$IntentionalAny, VoidFn} from '../../types'
|
||||||
import Stack from '../../utils/Stack'
|
import Stack from '../../utils/Stack'
|
||||||
import DerivationEmitter from '../DerivationEmitter'
|
|
||||||
import type {IDerivation} from '../IDerivation'
|
import type {IDerivation} from '../IDerivation'
|
||||||
import {isDerivation} from '../IDerivation'
|
import {isDerivation} from '../IDerivation'
|
||||||
import {
|
import {
|
||||||
|
@ -200,6 +199,8 @@ class HotHandle<V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const emptyObject = {}
|
||||||
|
|
||||||
class PrismDerivation<V> implements IDerivation<V> {
|
class PrismDerivation<V> implements IDerivation<V> {
|
||||||
/**
|
/**
|
||||||
* Whether the object is a derivation.
|
* Whether the object is a derivation.
|
||||||
|
@ -227,12 +228,31 @@ class PrismDerivation<V> implements IDerivation<V> {
|
||||||
listener: (v: V) => void,
|
listener: (v: V) => void,
|
||||||
immediate: boolean = false,
|
immediate: boolean = false,
|
||||||
): VoidFn {
|
): VoidFn {
|
||||||
const unsubscribe = new DerivationEmitter(this, ticker)
|
const dependent = () => {
|
||||||
.tappable()
|
ticker.onThisOrNextTick(refresh)
|
||||||
.tap(listener)
|
|
||||||
if (immediate) {
|
|
||||||
listener(this.getValue())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let lastValue = emptyObject
|
||||||
|
|
||||||
|
const refresh = () => {
|
||||||
|
const newValue = this.getValue()
|
||||||
|
if (newValue === lastValue) return
|
||||||
|
|
||||||
|
lastValue = newValue
|
||||||
|
listener(newValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addDependent(dependent)
|
||||||
|
|
||||||
|
if (immediate) {
|
||||||
|
lastValue = this.getValue()
|
||||||
|
listener(lastValue as $IntentionalAny as V)
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsubscribe = () => {
|
||||||
|
this.removeDependent(dependent)
|
||||||
|
}
|
||||||
|
|
||||||
return unsubscribe
|
return unsubscribe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -183,7 +183,7 @@ export const Scene: React.FC<{project: IProject}> = ({project}) => {
|
||||||
return studio.onSelectionChange((newState) => {
|
return studio.onSelectionChange((newState) => {
|
||||||
setSelection(newState)
|
setSelection(newState)
|
||||||
})
|
})
|
||||||
})
|
}, [])
|
||||||
|
|
||||||
const containerRef = useRef<HTMLDivElement>(null!)
|
const containerRef = useRef<HTMLDivElement>(null!)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue