SVG content does not re-render after state update when marker props are used on iOS
Description
When an SVG element (e.g. <Path>) uses the markerEnd prop, state changes that occur after mount do not cause the SVG to visually re-render on iOS. React processes the state update and re-renders the component tree correctly, but the SVG canvas never redraws — so any child element whose output depends on the updated state (e.g. a <Text> showing a counter) is stuck displaying the initial value.
Expected behavior: When state updates, the SVG should re-render and display the new values — e.g. the <Text> counter should advance from 0 to 1 after one second.
Actual behavior: The <Text> counter inside the SVG permanently shows 0. The state update fires (React processes it), but the SVG canvas never redraws to reflect it. The below reproduction is a trivial example, but it's a larger issue for us as we're building a whiteboard drawing application and this issue is preventing us from being able to allow users to draw paths with arrowheads in iOS as nothing is being re-rendered after the initial path is drawn.
Potential root cause (for maintainers): https://github.com/software-mansion/react-native-svg/blob/5b62c5d2597565cd4827b49aa0d6ab3546919879/apple/RNSVGNode.mm#L240-L250 when we comment out [self invalidate] when state changes a re-render is triggered and the updated counter is displayed.
Steps to reproduce
- Render a
<Svg>containing a<Defs>/<Marker>block and an element using the marker prop (e.g.marker="url(#selection)"). - Include a
<Text>inside the SVG that displays a state value. - In a
useEffect, usesetTimeoutto update that state value once after 1 second. - Run on iOS.
- Observe: the
<Text>inside the SVG shows0initially and never updates to1, even after the timeout fires. - Removing the
markerprop from the<Ellipse>causes the<Text>to update correctly.
Minimal reproduction:
Update ellipse example within this repo (apps/common/example/examples/Markers.tsx)
import React, { useEffect, useState } from 'react';
import { Circle, Defs, Ellipse, Marker, Svg, Text } from 'react-native-svg';
export default function EllipseExample() {
const [secondValue, setSecondValue] = useState(0);
useEffect(() => {
setTimeout(() => {
setSecondValue(v => v + 1);
}, 1000);
}, []);
return (
<Svg height="300" width="400">
<Defs>
<Marker
id="selection"
markerUnits="userSpaceOnUse"
refX="0"
refY="0"
orient="auto">
<Circle fill="#3a6cff" r={5} cx={0} cy={0} strokeWidth={1} stroke="white" />
</Marker>
</Defs>
{/* This text never updates from 0 to 1 when marker prop is present */}
<Text x={5} y={10} fill="black">{secondValue}</Text>
<Ellipse
cx="200" cy="170" rx="30%" ry="10%"
stroke="purple" strokeWidth="2" fill="yellow"
marker="url(#selection)"
/>
</Svg>
);
}Note: Removing marker="url(#selection)" from the <Ellipse> causes the <Text> to correctly update to 1 after one second.
Snack or a link to a repository
SVG version
15.15.4 (current version as defined in the package.json of this repo)
React Native version
^0.77.0 (current version as defined in the package.json of this repo)
Platforms
iOS
JavaScript runtime
Hermes
Workflow
React Native
Architecture
Fabric (New Architecture)
Build type
Debug app & dev bundle
Device
iOS simulator
Device model
iPhone 17
Acknowledgements
Yes
Source: software-mansion/react-native-svg