Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(loop): flushGlobalEffects for manual loop manipulation #2481

Merged
merged 3 commits into from Sep 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 16 additions & 15 deletions docs/API/additional-exports.mdx
Expand Up @@ -3,18 +3,19 @@ title: Additional Exports
nav: 9
---

| export | usage |
| ----------------- | -------------------------------------------------------------- |
| addEffect | Adds a global render callback which is called each frame |
| addAfterEffect | Adds a global after-render callback which is called each frame |
| addTail | Adds a global callback which is called when rendering stops |
| invalidate | Forces view global invalidation |
| advance | Advances the frameloop (given that it's set to 'never') |
| extend | Extends the native-object catalogue |
| createPortal | Creates a portal (it's a React feature for re-parenting) |
| createRoot | Creates a root that can render three JSX into a canvas |
| events | Dom pointer-event system |
| applyProps | `applyProps(element, props)` sets element properties, |
| act | usage with react-testing |
| useInstanceHandle | Exposes react-internal local state from `instance.__r3f` |
| | |
| export | usage |
| ------------------ | -------------------------------------------------------------- |
| addEffect | Adds a global render callback which is called each frame |
| addAfterEffect | Adds a global after-render callback which is called each frame |
| addTail | Adds a global callback which is called when rendering stops |
| flushGlobalEffects | Flushes global render-effects for when manually driving a loop |
| invalidate | Forces view global invalidation |
| advance | Advances the frameloop (given that it's set to 'never') |
| extend | Extends the native-object catalogue |
| createPortal | Creates a portal (it's a React feature for re-parenting) |
| createRoot | Creates a root that can render three JSX into a canvas |
| events | Dom pointer-event system |
| applyProps | `applyProps(element, props)` sets element properties, |
| act | usage with react-testing |
| useInstanceHandle | Exposes react-internal local state from `instance.__r3f` |
| | |
24 changes: 19 additions & 5 deletions packages/fiber/src/core/loop.ts
Expand Up @@ -35,9 +35,23 @@ export const addAfterEffect = (callback: GlobalRenderCallback) => createSubs(cal
export const addTail = (callback: GlobalRenderCallback) => createSubs(callback, globalTailEffects)

function run(effects: Set<SubItem>, timestamp: number) {
if (!effects.size) return
effects.forEach(({ callback }) => callback(timestamp))
}

export type GlobalEffectType = 'before' | 'after' | 'tail'

export function flushGlobalEffects(type: GlobalEffectType, timestamp: number): void {
switch (type) {
case 'before':
return run(globalEffects, timestamp)
case 'after':
return run(globalAfterEffects, timestamp)
case 'tail':
return run(globalTailEffects, timestamp)
}
}

let subscribers: Subscription[]
let subscription: Subscription
function render(timestamp: number, state: RootState, frame?: THREE.XRFrame) {
Expand Down Expand Up @@ -74,7 +88,7 @@ export function createLoop<TCanvas>(roots: Map<TCanvas, Root>) {
repeat = 0

// Run effects
if (globalEffects.size) run(globalEffects, timestamp)
flushGlobalEffects('before', timestamp)

// Render all roots
roots.forEach((root) => {
Expand All @@ -90,12 +104,12 @@ export function createLoop<TCanvas>(roots: Map<TCanvas, Root>) {
})

// Run after-effects
if (globalAfterEffects.size) run(globalAfterEffects, timestamp)
flushGlobalEffects('after', timestamp)

// Stop the loop if nothing invalidates it
if (repeat === 0) {
// Tail call effects, they are called when rendering stops
if (globalTailEffects.size) run(globalTailEffects, timestamp)
flushGlobalEffects('tail', timestamp)

// Flag end of operation
running = false
Expand All @@ -121,10 +135,10 @@ export function createLoop<TCanvas>(roots: Map<TCanvas, Root>) {
state?: RootState,
frame?: THREE.XRFrame,
): void {
if (runGlobalEffects) run(globalEffects, timestamp)
if (runGlobalEffects) flushGlobalEffects('before', timestamp)
if (!state) roots.forEach((root) => render(timestamp, root.store.getState()))
else render(timestamp, state, frame)
if (runGlobalEffects) run(globalAfterEffects, timestamp)
if (runGlobalEffects) flushGlobalEffects('after', timestamp)
}

return {
Expand Down