Skip to content

fix: dispose <primitive>-based effects, r3f never does it for them - #355

Open
kvvasuu wants to merge 1 commit into
fix/04-autofocus-double-disposefrom
fix/05-primitive-effect-dispose
Open

fix: dispose <primitive>-based effects, r3f never does it for them#355
kvvasuu wants to merge 1 commit into
fix/04-autofocus-double-disposefrom
fix/05-primitive-effect-dispose

Conversation

@kvvasuu

@kvvasuu kvvasuu commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Stacked PR 5/6 — part of a split of #350.
← based on #354 · → followed by #356

Fixes #344
Fixes #348

r3f explicitly never auto-disposes objects rendered via ("their state may be kept outside of React"), regardless of dispose={null}. Several effects that render this way had no cleanup at all (ASCII, ColorAverage, SelectiveBloom, SSAO), so they leaked their underlying postprocessing effect/texture on every unmount and every prop change that recreates the instance. Added a small useDispose hook (util.tsx) and wired it into every -based effect, with a WeakSet guard against double-dispose across StrictMode's dev-only mount/cleanup/mount cycle.

Also fixes GodRays, which was declared as (props, ref) without forwardRef - under React 19 that ref parameter is never populated, so consumers passing a ref to GodRays silently got nothing.

ChromaticAberration moves off wrapEffect onto the same manual construct-and-dispose pattern so its tuple offset prop coerces through useVector2 like the other vector-typed effects; test locks in that coercion.

Adds the ColorAverage dispose coverage to EffectComposer.test.tsx that the previous commit's suite deferred here, since ColorAverage didn't dispose itself until this fix landed.

r3f explicitly never auto-disposes objects rendered via <primitive
object={...}> ("their state may be kept outside of React"), regardless
of dispose={null}. Several effects that render this way had no cleanup
at all (ASCII, ColorAverage, SelectiveBloom, SSAO), so they leaked
their underlying postprocessing effect/texture on every unmount and
every prop change that recreates the instance. Added a small useDispose
hook (util.tsx) and wired it into every <primitive>-based effect, with
a WeakSet guard against double-dispose across StrictMode's dev-only
mount/cleanup/mount cycle.

Also fixes GodRays, which was declared as (props, ref) without
forwardRef - under React 19 that ref parameter is never populated, so
consumers passing a ref to GodRays silently got nothing.

ChromaticAberration moves off wrapEffect onto the same manual
construct-and-dispose pattern so its tuple `offset` prop coerces
through useVector2 like the other vector-typed effects; test locks in
that coercion.

Adds the ColorAverage dispose coverage to EffectComposer.test.tsx that
the previous commit's suite deferred here, since ColorAverage didn't
dispose itself until this fix landed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant