Before this, there was a delay between when a queued microtask is finished, and it being marked as so. If an update was queued in between this delay, it would have been missed.
This wasn't caught until now, because usually in a large react tree, usually there are one or more tickers that flush the queue, so if an update isn't picked up on one flush, it would end up in the next flush.
Remove cold derivation reads
Prior to this commit, the first render of every `useDerivation()` resulted in a cold read of its inner derivation. 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).
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.
Freshen derivations 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 value. Here is a contrived example:
```
const num = new Box(1)
const isPositiveD = prism(() => num.derivation.getValue() >= 0)
const Comp = () => {
return <div>{useDerivation(isPositiveD)}</div>
}
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.
This still avoids the zombie-child problem because `runQueue` reads the derivations 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 `useDerivation()` to be read inside a normal react render phase.
This implements some basic infra for testing Theatre.js with popular setups such as npm/yarn/pnpm, webpack/vite/parcel, js/ts, etc.
So far, the only existing setup has been with create-react-app. Will add more in the future.
Co-authored-by: Fülöp <fulopkovacs@users.noreply.github.com>
Co-authored-by: Aria Minaei <aria.minaei@gmail.com>