Unify Derivation and Prism 7/n
This commit is contained in:
parent
859cb40e0f
commit
acf34d393d
25 changed files with 134 additions and 141 deletions
|
@ -65,16 +65,16 @@ export function usePrism<T>(
|
|||
boxRef.current.set(fnAsCallback)
|
||||
}
|
||||
|
||||
const derivation = useMemo(
|
||||
const pr = useMemo(
|
||||
() =>
|
||||
prism(() => {
|
||||
const fn = boxRef.current.derivation.getValue()
|
||||
const fn = boxRef.current.prism.getValue()
|
||||
return fn()
|
||||
}),
|
||||
[],
|
||||
)
|
||||
|
||||
return useDerivation(derivation, debugLabel)
|
||||
return useDerivation(pr, debugLabel)
|
||||
}
|
||||
|
||||
export const useVal: typeof val = (p: $IntentionalAny, debugLabel?: string) => {
|
||||
|
@ -88,9 +88,9 @@ export const useVal: typeof val = (p: $IntentionalAny, debugLabel?: string) => {
|
|||
let lastOrder = 0
|
||||
|
||||
/**
|
||||
* A sorted array of derivations that need to be refreshed. The derivations are sorted
|
||||
* by their order, which means a parent derivation always gets priority to children
|
||||
* and descendents. Ie. we refresh the derivations top to bottom.
|
||||
* A sorted array of prisms that need to be refreshed. The prisms are sorted
|
||||
* by their order, which means a parent prism always gets priority to children
|
||||
* and descendents. Ie. we refresh the prisms top to bottom.
|
||||
*/
|
||||
const queue: QueueItem[] = []
|
||||
const setOfQueuedItems = new Set<QueueItem>()
|
||||
|
@ -99,7 +99,7 @@ type QueueItem<T = unknown> = {
|
|||
order: number
|
||||
/**
|
||||
* runUpdate() is the equivalent of a forceUpdate() call. It would only be called
|
||||
* if the value of the inner derivation has _actually_ changed.
|
||||
* if the value of the inner prism has _actually_ changed.
|
||||
*/
|
||||
runUpdate: VoidFn
|
||||
/**
|
||||
|
@ -142,11 +142,11 @@ type QueueItem<T = unknown> = {
|
|||
>
|
||||
}
|
||||
/**
|
||||
* A reference to the derivation
|
||||
* A reference to the prism
|
||||
*/
|
||||
der: Prism<T>
|
||||
/**
|
||||
* The last value of this derivation.
|
||||
* The last value of this prism.
|
||||
*/
|
||||
lastValue: T
|
||||
/**
|
||||
|
@ -246,17 +246,17 @@ function queueIfNeeded() {
|
|||
})
|
||||
}
|
||||
/**
|
||||
* A React hook that returns the value of the derivation that it received as the first argument.
|
||||
* A React hook that returns the value of the prism that it received as the first argument.
|
||||
* It works like an implementation of Dataverse's Ticker, except that it runs the side effects in
|
||||
* an order where a component's derivation is guaranteed to run before any of its descendents' derivations.
|
||||
* an order where a component's prism is guaranteed to run before any of its descendents' prisms.
|
||||
*
|
||||
* @param der - The derivation
|
||||
* @param der - The prism
|
||||
* @param debugLabel - The label used by the debugger
|
||||
*
|
||||
* @remarks
|
||||
* It looks like this new implementation of useDerivation() manages to:
|
||||
* 1. Not over-calculate the derivations
|
||||
* 2. Render derivation in ancestor -\> descendent order
|
||||
* It looks like this new implementation of usePrism() manages to:
|
||||
* 1. Not over-calculate the prisms
|
||||
* 2. Render prism in ancestor -\> descendent order
|
||||
* 3. Not set off React's concurrent mode alarms
|
||||
*
|
||||
*
|
||||
|
@ -266,21 +266,21 @@ function queueIfNeeded() {
|
|||
*
|
||||
* Notes on the latest implementation:
|
||||
*
|
||||
* # Remove cold derivation reads
|
||||
* # Remove cold prism reads
|
||||
*
|
||||
* Prior to the latest change, the first render of every `useDerivation()` resulted in a cold read of its inner derivation.
|
||||
* Prior to the latest change, the first render of every `useDerivation()` resulted in a cold read of its inner prism.
|
||||
* Cold reads are predictably slow. The reason we'd run cold reads was to comply with react's rule of not running side-effects
|
||||
* during render. (Turning a derivation hot is _technically_ a side-effect).
|
||||
* during render. (Turning a prism hot is _technically_ a side-effect).
|
||||
*
|
||||
* However, now that users are animating scenes with hundreds of objects in the same sequence, the lag started to be noticable.
|
||||
*
|
||||
* This commit changes `useDerivation()` so that it turns its derivation hot before rendering them.
|
||||
* This commit changes `useDerivation()` so that it turns its prism hot before rendering them.
|
||||
*
|
||||
* # Freshen derivations before render
|
||||
* # Freshen prisms before render
|
||||
*
|
||||
* Previously in order to avoid the zombie child problem (https://kaihao.dev/posts/stale-props-and-zombie-children-in-redux)
|
||||
* we deferred freshening the derivations to the render phase of components. This meant that if a derivation's dependencies
|
||||
* changed, `useDerivation()` would schedule a re-render, regardless of whether that change actually affected the derivation's
|
||||
* we deferred freshening the prisms to the render phase of components. This meant that if a prism's dependencies
|
||||
* changed, `useDerivation()` would schedule a re-render, regardless of whether that change actually affected the prism's
|
||||
* value. Here is a contrived example:
|
||||
*
|
||||
* ```ts
|
||||
|
@ -294,10 +294,10 @@ function queueIfNeeded() {
|
|||
* num.set(2) // would cause Comp to re-render- even though 1 is still a positive number
|
||||
* ```
|
||||
*
|
||||
* We now avoid this problem by freshening the derivation (i.e. calling `der.getValue()`) inside `runQueue()`,
|
||||
* and then only causing a re-render if the derivation's value is actually changed.
|
||||
* We now avoid this problem by freshening the prism (i.e. calling `der.getValue()`) inside `runQueue()`,
|
||||
* and then only causing a re-render if the prism's value is actually changed.
|
||||
*
|
||||
* This still avoids the zombie-child problem because `runQueue` reads the derivations in-order of their position in
|
||||
* This still avoids the zombie-child problem because `runQueue` reads the prisms in-order of their position in
|
||||
* the mounting tree.
|
||||
*
|
||||
* On the off-chance that one of them still turns out to be a zombile child, `runQueue` will defer that particular
|
||||
|
@ -374,29 +374,29 @@ export function useDerivation<T>(der: Prism<T>, debugLabel?: string): T {
|
|||
}
|
||||
|
||||
/**
|
||||
* This makes sure the prism derivation remains hot as long as the
|
||||
* This makes sure the prism prism remains hot as long as the
|
||||
* component calling the hook is alive, but it does not
|
||||
* return the value of the derivation, and it does not
|
||||
* re-render the component if the value of the derivation changes.
|
||||
* return the value of the prism, and it does not
|
||||
* re-render the component if the value of the prism changes.
|
||||
*
|
||||
* Use this hook if you plan to read a derivation in a
|
||||
* useEffect() call, without the derivation causing your
|
||||
* Use this hook if you plan to read a prism in a
|
||||
* useEffect() call, without the prism causing your
|
||||
* element to re-render.
|
||||
*/
|
||||
export function usePrismWithoutReRender<T>(
|
||||
fn: () => T,
|
||||
deps: unknown[],
|
||||
): Prism<T> {
|
||||
const derivation = useMemo(() => prism(fn), deps)
|
||||
const pr = useMemo(() => prism(fn), deps)
|
||||
|
||||
return useDerivationWithoutReRender(derivation)
|
||||
return useDerivationWithoutReRender(pr)
|
||||
}
|
||||
|
||||
/**
|
||||
* This makes sure the derivation remains hot as long as the
|
||||
* This makes sure the prism remains hot as long as the
|
||||
* component calling the hook is alive, but it does not
|
||||
* return the value of the derivation, and it does not
|
||||
* re-render the component if the value of the derivation changes.
|
||||
* return the value of the prism, and it does not
|
||||
* re-render the component if the value of the prism changes.
|
||||
*/
|
||||
export function useDerivationWithoutReRender<T>(der: Prism<T>): Prism<T> {
|
||||
useEffect(() => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue