fix: dispose <primitive>-based effects, r3f never does it for them - #355
Open
kvvasuu wants to merge 1 commit into
Open
fix: dispose <primitive>-based effects, r3f never does it for them#355kvvasuu wants to merge 1 commit into
kvvasuu wants to merge 1 commit into
Conversation
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.
This was referenced Jul 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
offsetprop 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.