software-mansion / react-native-svg

SVG library for React Native, React Native Web, and plain React web projects.
MIT License
7.42k stars 1.12k forks source link

ForeignObject does not rerender #1357

Open florian-milky opened 4 years ago

florian-milky commented 4 years ago

Bug

Components inside ForeignObject don't rerender properly.

Repro

https://snack.expo.io/@d0m3/foreignobject-no-render

workaround

Add key to ForeignObject to control rendering

oleksandr-dziuban commented 4 years ago

@florian-milky I have same issue @msand Could you please check? Thank you

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. You may also mark this issue as a "discussion" and I will leave this open.

alicema15 commented 4 years ago

I'm also running into this issue - any updates?

egorshulga commented 3 years ago

Still an issue. Is there anything we can provide?

alicema15 commented 3 years ago

Upon digging further, it seems like the ForeignObject is freezing rendering of any kind - for example, a GIF inside a react-native-fast-image component doesn't move either.

I've found a workaround by adding a key to the ForeignObject and manually re-triggering a render as @florian-milky suggested - but this is quite hacky. In case anyone needs it, you don't need to modify the source code, this worked for me:

import { ForeignObject, SVG } from 'react-native-svg';

<Svg>
  <ForeignObject
    key={key}
  >
      // render item
  </ForeignObject>
</Svg>

Where we're changing the key every time we want the ForeignObject to rerender.

However, I'm lately running into another issue where images aren't loading when we change the image inside the object. It's quite strange and I'm wondering if anyone has any insights?

St1ggy commented 3 years ago

@florian-milky @alicema15 Unfortunately, it doesn't work for any Images :(

mlecoq commented 3 years ago

Adding a key on a animated component (with reanimated v2) raises another behavior issues. Unfortunately this workaround don't work in my use case : text modifications (displayed in ReText - from redash) are only displayed when one of AnimatedForeignObject prop (position in my case) is updated

const AnimatedForeignObject = Animated.createAnimatedComponent(ForeignObject);
<AnimatedForeignObject animatedProps={textAnimatedProps}>
        <Animated.View
          style={textAnimatedPropsContainer}
          onLayout={(event) => onHeightChange(event.nativeEvent.layout.height)}
        >
          <View
            style={{
              marginHorizontal: 10,
              backgroundColor: "rgba(0, 0, 0, 0.6)",
              borderRadius: 10,
              paddingVertical: 13,
              paddingHorizontal: 18,
            }}
          >
            <ReText text={textContentProps} />
          </View>
        </Animated.View>
      </AnimatedForeignObject>
kinkin626 commented 2 years ago

Any update here? I am facing the same issue @mlecoq @St1ggy @alicema15

zemuldo commented 2 years ago

Any update here? I am facing the same issue @mlecoq @St1ggy @alicema15

+1

talon-himself commented 2 years ago

@alicema15 @florian-milky I am adding a key and it still isn't working. How are you changing the key every time you want the ForeignObject to rerender?

dwolfand commented 1 year ago

Bumping this issue as we are running into this too.

MuhammedEl-Sayed commented 1 year ago

Have same issue, specifically when using react-navigation when navigating inbetween screens. Forcing the ForeignObject to re-render seems to fix the issue, but interestingly, as seen in the code below, it only required forcing one mapping of ForeignObjects to rerender to fix both in the SVG, which doesn't make much sense to me.

{labelPoints.map((point, index) => {
        return (
              <ForeignObject x={point.x} y={point.y} key={index + fOfix}>
                        <ContentText style={{ textAlign: "center", fontSize: 40, color: textColor }}>{labels[index]}</ContentText>
              </ForeignObject>
                        )
        })}
{measurementLabels.map((label, index) => {
        return (
               <ForeignObject x={measurementPoints[index].x} y={measurementPoints[index].y} key={index}>
                        <ContentText style={{ textAlign: "center", fontSize: 40, color: textColor }}>{label}</ContentText>
               </ForeignObject>
                        )
                    })}
)}

and this is how it is updated:

    const isFocused = useIsFocused();
    const [fOfix, setFOfix] = useState(0);
    useEffect(() => {
        setFOfix(fOfix + 1)
    }, [isFocused])

Not sure what is going on, but looks like forcing rerenders is the fix for now