diff --git a/docs/API/additional-exports.mdx b/docs/API/additional-exports.mdx index acb1d868e2..1665ac75b9 100644 --- a/docs/API/additional-exports.mdx +++ b/docs/API/additional-exports.mdx @@ -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` | +| | | diff --git a/packages/fiber/src/core/loop.ts b/packages/fiber/src/core/loop.ts index c61b102774..1d314ff5f7 100644 --- a/packages/fiber/src/core/loop.ts +++ b/packages/fiber/src/core/loop.ts @@ -35,9 +35,23 @@ export const addAfterEffect = (callback: GlobalRenderCallback) => createSubs(cal export const addTail = (callback: GlobalRenderCallback) => createSubs(callback, globalTailEffects) function run(effects: Set, 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) { @@ -74,7 +88,7 @@ export function createLoop(roots: Map) { repeat = 0 // Run effects - if (globalEffects.size) run(globalEffects, timestamp) + flushGlobalEffects('before', timestamp) // Render all roots roots.forEach((root) => { @@ -90,12 +104,12 @@ export function createLoop(roots: Map) { }) // 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 @@ -121,10 +135,10 @@ export function createLoop(roots: Map) { 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 {