Simplify Derivation.onChange()

It no longer uses `DerivationEmitter`.
This commit is contained in:
Aria Minaei 2022-12-01 14:06:09 +01:00
parent a24a149a52
commit 194de8d833
3 changed files with 27 additions and 71 deletions

View file

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

View file

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

View file

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