Add initial tools for managing derivations and React compatibility (#202)
Co-authored-by: Cole Lawrence <cole@colelawrence.com> Co-authored-by: Elliot <key.draw@gmail.com> Co-authored-by: Aria <aria.minaei@gmail.com>
This commit is contained in:
parent
bebf281517
commit
f1844952ea
12 changed files with 320 additions and 30 deletions
|
@ -201,7 +201,9 @@ export default class Atom<State extends {}>
|
|||
|
||||
private _checkUpdates(scope: Scope, oldState: unknown, newState: unknown) {
|
||||
if (oldState === newState) return
|
||||
scope.identityChangeListeners.forEach((cb) => cb(newState))
|
||||
for (const cb of scope.identityChangeListeners) {
|
||||
cb(newState)
|
||||
}
|
||||
|
||||
if (scope.children.size === 0) return
|
||||
|
||||
|
@ -212,11 +214,11 @@ export default class Atom<State extends {}>
|
|||
if (oldValueType === ValueTypes.Other && oldValueType === newValueType)
|
||||
return
|
||||
|
||||
scope.children.forEach((childScope, childKey) => {
|
||||
for (const [childKey, childScope] of scope.children) {
|
||||
const oldChildVal = getKeyOfValue(oldState, childKey, oldValueType)
|
||||
const newChildVal = getKeyOfValue(newState, childKey, newValueType)
|
||||
this._checkUpdates(childScope, oldChildVal, newChildVal)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private _getOrCreateScopeForPath(path: (string | number)[]): Scope {
|
||||
|
|
|
@ -121,9 +121,10 @@ export default class Ticker {
|
|||
tick(t: number = performance.now()) {
|
||||
this._ticking = true
|
||||
this._timeAtCurrentTick = t
|
||||
this._scheduledForNextTick.forEach((v) =>
|
||||
this._scheduledForThisOrNextTick.add(v),
|
||||
)
|
||||
for (const v of this._scheduledForNextTick) {
|
||||
this._scheduledForThisOrNextTick.add(v)
|
||||
}
|
||||
|
||||
this._scheduledForNextTick.clear()
|
||||
this._tick(0)
|
||||
this._ticking = false
|
||||
|
@ -142,9 +143,9 @@ export default class Ticker {
|
|||
|
||||
const oldSet = this._scheduledForThisOrNextTick
|
||||
this._scheduledForThisOrNextTick = new Set()
|
||||
oldSet.forEach((fn) => {
|
||||
for (const fn of oldSet) {
|
||||
fn(time)
|
||||
})
|
||||
}
|
||||
|
||||
if (this._scheduledForThisOrNextTick.size > 0) {
|
||||
return this._tick(iterationNumber + 1)
|
||||
|
|
|
@ -170,9 +170,9 @@ export default abstract class AbstractDerivation<V> implements IDerivation<V> {
|
|||
this._didMarkDependentsAsStale = true
|
||||
this._isFresh = false
|
||||
|
||||
this._dependents.forEach((dependent) => {
|
||||
for (const dependent of this._dependents) {
|
||||
dependent(this)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -228,14 +228,14 @@ export default abstract class AbstractDerivation<V> implements IDerivation<V> {
|
|||
this._didMarkDependentsAsStale = false
|
||||
this._isFresh = false
|
||||
if (shouldBecomeHot) {
|
||||
this._dependencies.forEach((d) => {
|
||||
for (const d of this._dependencies) {
|
||||
d.addDependent(this._internal_markAsStale)
|
||||
})
|
||||
}
|
||||
this._keepHot()
|
||||
} else {
|
||||
this._dependencies.forEach((d) => {
|
||||
for (const d of this._dependencies) {
|
||||
d.removeDependent(this._internal_markAsStale)
|
||||
})
|
||||
}
|
||||
this._becomeCold()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,18 +70,18 @@ export class PrismDerivation<V> extends AbstractDerivation<V> {
|
|||
|
||||
popCollector(collector)
|
||||
|
||||
this._dependencies.forEach((dep) => {
|
||||
for (const dep of this._dependencies) {
|
||||
if (!newDeps.has(dep)) {
|
||||
this._removeDependency(dep)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this._dependencies = newDeps
|
||||
|
||||
startIgnoringDependencies()
|
||||
newDeps.forEach((dep) => {
|
||||
for (const dep of newDeps) {
|
||||
this._cacheOfDendencyValues.set(dep, dep.getValue())
|
||||
})
|
||||
}
|
||||
stopIgnoringDependencies()
|
||||
|
||||
return value!
|
||||
|
|
|
@ -20,17 +20,14 @@ export default class Emitter<V> {
|
|||
this._lastTapperId = 0
|
||||
this._tappers = new Map()
|
||||
this.tappable = new Tappable({
|
||||
tapToSource: (cb: Tapper<V>) => {
|
||||
return this._tap(cb)
|
||||
},
|
||||
tapToSource: (cb: Tapper<V>) => this._tap(cb),
|
||||
})
|
||||
}
|
||||
|
||||
_tap(cb: Tapper<V>): Untap {
|
||||
const tapperId = this._lastTapperId++
|
||||
this._tappers.set(tapperId, cb)
|
||||
this._onNumberOfTappersChangeListener &&
|
||||
this._onNumberOfTappersChangeListener(this._tappers.size)
|
||||
this._onNumberOfTappersChangeListener?.(this._tappers.size)
|
||||
return () => {
|
||||
this._removeTapperById(tapperId)
|
||||
}
|
||||
|
@ -41,8 +38,7 @@ export default class Emitter<V> {
|
|||
this._tappers.delete(id)
|
||||
const newSize = this._tappers.size
|
||||
if (oldSize !== newSize) {
|
||||
this._onNumberOfTappersChangeListener &&
|
||||
this._onNumberOfTappersChangeListener(this._tappers.size)
|
||||
this._onNumberOfTappersChangeListener?.(newSize)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,9 +48,9 @@ export default class Emitter<V> {
|
|||
* @param payload - The value to be emitted.
|
||||
*/
|
||||
emit(payload: V) {
|
||||
this._tappers.forEach((cb) => {
|
||||
for (const cb of this._tappers.values()) {
|
||||
cb(payload)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -53,9 +53,9 @@ export default class Tappable<V> {
|
|||
}
|
||||
|
||||
private _cb: any = (arg: any): void => {
|
||||
this._tappers.forEach((cb) => {
|
||||
for (const cb of this._tappers.values()) {
|
||||
cb(arg)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -179,7 +179,7 @@ function queueIfNeeded() {
|
|||
*
|
||||
* I'm happy with how little bookkeeping we ended up doing here.
|
||||
*/
|
||||
function useDerivation<T>(der: IDerivation<T>, debugLabel?: string): T {
|
||||
export function useDerivation<T>(der: IDerivation<T>, debugLabel?: string): T {
|
||||
const _forceUpdate = useForceUpdate(debugLabel)
|
||||
|
||||
const refs = useRef<{queueItem: QueueItem; unmounted: boolean}>(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue