Skip to content

fix: reset color on view recycle so currentColor does not leak between recycled SVG views (iOS, Fabric) - #2991

Open
aaronhu-apex wants to merge 1 commit into
software-mansion:mainfrom
aaronhu-apex:fix/svgview-color-recycling
Open

fix: reset color on view recycle so currentColor does not leak between recycled SVG views (iOS, Fabric)#2991
aaronhu-apex wants to merge 1 commit into
software-mansion:mainfrom
aaronhu-apex:fix/svgview-color-recycling

Conversation

@aaronhu-apex

Copy link
Copy Markdown

Summary

Fixes #2566.

On the new architecture, iOS recycles component views by default. RNSVGSvgView has two compounding issues that make the recycled view keep the previous instance's color:

  1. updateProps: only assigns self.color when the incoming color is non-null — an SVG mounted without a color prop never overwrites the recycled view's stale value:
if (RCTUIColorFromSharedColor(newProps.color)) {
  self.color = RCTUIColorFromSharedColor(newProps.color);
}
  1. prepareForRecycle resets viewBox / bounding-box / transform state but not _color.

Since currentColor resolution walks up the tree and terminates at the root svg view's color (RNSVGRenderable getCurrentColor), any element rendered with stroke="currentColor" / fill="currentColor" and no explicit color up its chain paints with whatever color the recycled root happened to carry from its previous life. This is exactly the intermittent wrong-color symptom in #2566: it depends on recycle-pool order, typically shows up after navigation (screens/sheets unmounting), and a reload "fixes" it.

This is very easy to hit with lucide-react-native, where every icon is stroke="currentColor" by default: render one icon with color="white" on screen A (its svg root view gets color = white, then gets recycled), then mount an icon with no color prop on screen B — it intermittently renders white.

The fix: assign self.color unconditionally in updateProps: (nil clears it, matching a prop that was unset or removed), and reset _color = nil in prepareForRecycle alongside the other fields.

Impact: apple/Elements/RNSVGSvgView.mm only.

Test Plan

Reproduced in a React Native app (Expo SDK 57 / RN 0.86, new architecture) where lucide icons intermittently rendered white after closing a bottom sheet containing color="white" icons — a header back-arrow (<ArrowLeft size={24} />, no color prop) picked up the recycled white root. Applied this change via patch-package, rebuilt, and the wrong-color rendering no longer occurs.

What's required for testing (prerequisites)?

iOS app on the new architecture with view recycling active (default).

What are the steps to reproduce (after prerequisites)?

  1. Screen A: render an SVG relying on currentColor with an explicit root color, e.g. <SomeLucideIcon color="white" /> (or any <Svg color="red"> with stroke="currentColor" children).
  2. Unmount screen A (navigate away / close a sheet) so its views enter the recycle pool.
  3. Screen B: mount an SVG that uses currentColor without a color prop.
  4. Before the fix, the screen-B SVG intermittently paints with screen A's color (pool-order dependent — repeat a few times). After the fix, it always uses the default.

Compatibility

OS Implemented
iOS
MacOS
Android
Web

Checklist

  • I have tested this on a device and a simulator
  • I added documentation in README.md
  • I updated the typed files (typescript)
  • I added a test for the API in the __tests__ folder

🤖 Generated with Claude Code

…n recycled SVG views on iOS

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

currentColor not using correct color sometimes

1 participant