mirror of
https://github.com/re-rxjs/react-rxjs.git
synced 2025-12-08 18:01:51 +00:00
chore: avoid passing parentState to internal run
This commit is contained in:
parent
96b1997c95
commit
516dbed517
@ -1,12 +1,6 @@
|
||||
import { NestedMap } from "./internal/nested-map"
|
||||
import { of } from "rxjs"
|
||||
import {
|
||||
mapRecord,
|
||||
detachedNode,
|
||||
EMPTY_VALUE,
|
||||
recordEntries,
|
||||
children,
|
||||
} from "./internal"
|
||||
import { mapRecord, detachedNode, recordEntries, children } from "./internal"
|
||||
import { StateNode, StringRecord } from "./types"
|
||||
|
||||
type StringRecordNodeToNodeStringRecord<
|
||||
@ -20,43 +14,47 @@ export const combineStates = <States extends StringRecord<StateNode<any>>>(
|
||||
): StringRecordNodeToNodeStringRecord<States> => {
|
||||
const instances = new NestedMap()
|
||||
const nKeys = Object.keys(states).length
|
||||
const _activeStates = mapRecord(states, () => false)
|
||||
const _latestStates = mapRecord(states, () => null)
|
||||
const _allFalse = mapRecord(states, () => false)
|
||||
|
||||
const [result, run] = detachedNode((ctx) =>
|
||||
of(mapRecord(states, (node) => ctx(node))),
|
||||
)
|
||||
|
||||
let latestValue: boolean | EMPTY_VALUE = false
|
||||
recordEntries(states).forEach(([key, node]) => {
|
||||
children.get(node)!.add((ctxKey, isActive, value) => {
|
||||
children.get(node)!.add((ctxKey, isActive, isParentLoaded) => {
|
||||
let instance: any = instances.get(ctxKey)
|
||||
if (!instance) {
|
||||
instance = {
|
||||
inactiveStates: nKeys,
|
||||
activeStates: { ..._activeStates },
|
||||
latestStates: { ..._latestStates },
|
||||
emptyStates: nKeys,
|
||||
activeStates: { ..._allFalse },
|
||||
loadedStates: { ..._allFalse },
|
||||
latestIsActive: null,
|
||||
latestIsLoaded: null,
|
||||
}
|
||||
instances.set(ctxKey, instance)
|
||||
}
|
||||
|
||||
if (isActive !== instance.activeStates[key]) {
|
||||
instance.inactiveStates += isActive ? -1 : +1
|
||||
instance.inactiveStates += isActive ? -1 : 1
|
||||
instance.activeStates[key] = isActive
|
||||
}
|
||||
|
||||
if (value !== instance.latestStates[key]) {
|
||||
instance.emptyStates +=
|
||||
instance.latestStates[key] === EMPTY_VALUE
|
||||
? -1
|
||||
: value === EMPTY_VALUE
|
||||
? 1
|
||||
: 0
|
||||
instance.latestStates[key] = value
|
||||
if (isParentLoaded !== instance.loadedStates[key]) {
|
||||
instance.emptyStates += isParentLoaded ? -1 : 1
|
||||
instance.loadedStates[key] = isParentLoaded
|
||||
}
|
||||
|
||||
latestValue = instance.emptyStates === 0 ? !latestValue : EMPTY_VALUE
|
||||
run(ctxKey, instance.inactiveStates === 0, instance.latestValue)
|
||||
const isCurrentlyActive = instance.inactiveStates === 0
|
||||
const isLoaded = instance.activeStates === nKeys
|
||||
if (
|
||||
isCurrentlyActive !== instance.latestIsActive ||
|
||||
isLoaded !== instance.latestIsLoaded
|
||||
) {
|
||||
instance.latestIsActive = isCurrentlyActive
|
||||
instance.latestIsLoaded = isLoaded
|
||||
run(ctxKey, isCurrentlyActive, isLoaded)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -7,11 +7,11 @@ export interface RootNode extends StateNode<never> {
|
||||
|
||||
export function createRoot(): RootNode {
|
||||
const childRunners = new Set<
|
||||
(key: any, isActive: boolean, value: null) => void
|
||||
(key: any, isActive: boolean, value?: boolean) => void
|
||||
>()
|
||||
const runChildren = (key: any, isActive: boolean) => {
|
||||
childRunners.forEach((cb) => {
|
||||
cb(key, isActive, null)
|
||||
cb(key, isActive, true)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import { StateNode } from "../types"
|
||||
import { EMPTY_VALUE } from "./empty-value"
|
||||
|
||||
export interface RunFn<P> {
|
||||
(key: any, isActive: boolean, parentValue?: P | EMPTY_VALUE): void
|
||||
export interface RunFn {
|
||||
(key: any[], isActive: boolean, isParentLoaded?: boolean): void
|
||||
}
|
||||
|
||||
export const children = new WeakMap<StateNode<any>, Set<RunFn<any>>>()
|
||||
export const children = new WeakMap<StateNode<any>, Set<RunFn>>()
|
||||
|
||||
@ -12,17 +12,17 @@ import {
|
||||
} from "./"
|
||||
import { NestedMap } from "./nested-map"
|
||||
|
||||
export const detachedNode = <T, P>(
|
||||
export const detachedNode = <T>(
|
||||
getState$: (ctx: Ctx) => Observable<T>,
|
||||
equalityFn: (a: T, b: T) => boolean = Object.is,
|
||||
): [StateNode<T>, RunFn<P>] => {
|
||||
): [StateNode<T>, RunFn] => {
|
||||
const instances = new NestedMap<
|
||||
any,
|
||||
{
|
||||
subject: ReplaySubject<T>
|
||||
subscription: Subscription | null
|
||||
currentValue: EMPTY_VALUE | T
|
||||
currentParentValue: EMPTY_VALUE
|
||||
isParentLoaded: boolean
|
||||
promise: DeferredPromise<T> | null
|
||||
}
|
||||
>()
|
||||
@ -45,16 +45,16 @@ export const detachedNode = <T, P>(
|
||||
}),
|
||||
}
|
||||
|
||||
const childRunners = new Set<RunFn<T>>()
|
||||
const childRunners = new Set<RunFn>()
|
||||
children.set(result, childRunners)
|
||||
|
||||
const runChildren: RunFn<T> = (...args) => {
|
||||
const runChildren: RunFn = (...args) => {
|
||||
childRunners.forEach((cb) => {
|
||||
cb(...args)
|
||||
})
|
||||
}
|
||||
|
||||
const run = (key: any[], isActive: boolean, parentValue: any) => {
|
||||
const run = (key: any[], isActive: boolean, isParentLoaded?: boolean) => {
|
||||
let instance = instances.get(key)
|
||||
if (!isActive) {
|
||||
if (!instance) return
|
||||
@ -68,7 +68,7 @@ export const detachedNode = <T, P>(
|
||||
return
|
||||
}
|
||||
|
||||
if (parentValue !== EMPTY_VALUE) {
|
||||
if (isParentLoaded) {
|
||||
// an actual change of context
|
||||
const hasPreviousValue = instance && instance.currentValue !== EMPTY_VALUE
|
||||
if (!instance) {
|
||||
@ -76,14 +76,14 @@ export const detachedNode = <T, P>(
|
||||
subject: new ReplaySubject<T>(1),
|
||||
subscription: null,
|
||||
currentValue: EMPTY_VALUE,
|
||||
currentParentValue: EMPTY_VALUE,
|
||||
isParentLoaded,
|
||||
promise: null,
|
||||
}
|
||||
instances.set(key, instance)
|
||||
} else {
|
||||
instance.subscription?.unsubscribe()
|
||||
instance.currentValue = EMPTY_VALUE
|
||||
instance.currentParentValue = parentValue
|
||||
instance.isParentLoaded = true
|
||||
}
|
||||
const actualInstance = instance
|
||||
|
||||
@ -103,7 +103,6 @@ export const detachedNode = <T, P>(
|
||||
delete (actualInstance as any).subject
|
||||
|
||||
actualInstance.currentValue = EMPTY_VALUE
|
||||
actualInstance.currentParentValue = EMPTY_VALUE
|
||||
|
||||
runChildren(key, false)
|
||||
prevPromise?.rej(err)
|
||||
@ -126,7 +125,7 @@ export const detachedNode = <T, P>(
|
||||
actualInstance.promise = null
|
||||
if (prevValue === EMPTY_VALUE || !equalityFn(prevValue, value)) {
|
||||
prevPromise?.res(value)
|
||||
runChildren(key, true, value)
|
||||
runChildren(key, true, true)
|
||||
actualInstance.subject!.next(value)
|
||||
}
|
||||
},
|
||||
@ -148,32 +147,32 @@ export const detachedNode = <T, P>(
|
||||
prevSubect = actualInstance.subject
|
||||
actualInstance.subject = new ReplaySubject<T>(1)
|
||||
}
|
||||
runChildren(key, true, EMPTY_VALUE)
|
||||
runChildren(key, true, false)
|
||||
prevSubect?.complete()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// at this point parentValue is EMPTY_VALUE
|
||||
if (instance?.currentParentValue === EMPTY_VALUE) return
|
||||
if (instance?.isParentLoaded === false) return
|
||||
|
||||
const prevSubect = instance?.subject
|
||||
if (instance) {
|
||||
instance.subject = new ReplaySubject<T>(1)
|
||||
instance.subscription?.unsubscribe()
|
||||
instance.subscription = null
|
||||
instance.currentValue = EMPTY_VALUE
|
||||
instance.currentParentValue = EMPTY_VALUE
|
||||
instance.isParentLoaded = false
|
||||
} else {
|
||||
instance = {
|
||||
subject: new ReplaySubject<T>(1),
|
||||
subscription: null,
|
||||
currentValue: EMPTY_VALUE,
|
||||
currentParentValue: EMPTY_VALUE,
|
||||
isParentLoaded: false,
|
||||
promise: null,
|
||||
}
|
||||
instances.set(key, instance)
|
||||
}
|
||||
runChildren(key, true, EMPTY_VALUE)
|
||||
runChildren(key, true, false)
|
||||
prevSubect?.complete()
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,4 @@
|
||||
import {
|
||||
EMPTY_VALUE,
|
||||
children,
|
||||
mapRecord,
|
||||
detachedNode,
|
||||
recordEntries,
|
||||
} from "./internal"
|
||||
import { children, mapRecord, detachedNode, recordEntries } from "./internal"
|
||||
import { of } from "rxjs"
|
||||
import { substate } from "./substate"
|
||||
import { StateNode, Ctx } from "./types"
|
||||
@ -27,7 +21,7 @@ export const routeState = <
|
||||
const keyState = substate(parent, (ctx) => of(selector(ctx(parent), ctx)))
|
||||
|
||||
const routedState = mapRecord(routes, (mapper) =>
|
||||
detachedNode<any, any>((ctx) => {
|
||||
detachedNode<any>((ctx) => {
|
||||
const parentValue = ctx(parent)
|
||||
return of(mapper ? mapper(parentValue) : parentValue)
|
||||
}),
|
||||
@ -37,18 +31,11 @@ export const routeState = <
|
||||
recordEntries(routedState).map(([key, value]) => [key, value[1]]),
|
||||
)
|
||||
|
||||
const run = (
|
||||
ctxKey: any[],
|
||||
isActive: boolean,
|
||||
value: keyof O | EMPTY_VALUE,
|
||||
) => {
|
||||
if (!isActive || value === EMPTY_VALUE)
|
||||
runners.forEach((runner) => {
|
||||
runner(ctxKey, false)
|
||||
})
|
||||
|
||||
const run = (ctxKey: any[], isActive: boolean, isParentLoaded?: boolean) => {
|
||||
const activeKey =
|
||||
isActive && isParentLoaded ? keyState.getValue(ctxKey) : null
|
||||
runners.forEach((runner, key) => {
|
||||
if (key === value) runner(ctxKey, true, value)
|
||||
if (key === activeKey) runner(ctxKey, true, true)
|
||||
else runner(ctxKey, false)
|
||||
})
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ export const substate = <T, P>(
|
||||
getState$: (ctx: Ctx) => Observable<T>,
|
||||
equalityFn: (a: T, b: T) => boolean = Object.is,
|
||||
): StateNode<T> => {
|
||||
const [result, run] = detachedNode<T, P>(getState$, equalityFn)
|
||||
const [result, run] = detachedNode<T>(getState$, equalityFn)
|
||||
children.get(parent)!.add(run)
|
||||
return result
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user