Scenario: I have an svg circle
and a state
rendered on the screen. I also have two buttons. Change Size
button changes the size (shared value) of the circle from 50 to 100 or 100 to 50. Change State button changes the state from 'apple' to 'orange' or 'orange' to 'apple'.
[Note: Animation does not use the state in any way. I am also console logging the size.value
in every rerender]
Issue: Once the Change Size
button is pressed, it animates the circle from 50 to 100. Now if you press Change State
button, it changes the state but it also makes the size of the circle back to 50 although our log shows that the shared value size.value
is still 100.
Expected Behavior: Expected the size of the circle to remain 100 as that is the shared value supplied to the circle.
Code:
import React, {useState, useEffect} from 'react';
import { Text, View, Button} from 'react-native';
import Animated, {
useAnimatedProps,
useSharedValue,
withSpring,
} from 'react-native-reanimated';
import Svg, {Circle} from 'react-native-svg';
const App = () => {
const [state, setState] = useState('apple');
const size = useSharedValue(50);
const animatedProps = useAnimatedProps(() => {
return {
r: size.value / 2,
};
});
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
useEffect(() => {
console.log('size.value =', size.value);
});
return (
<View style={{flex: 1}}>
<Svg height={100} width={100}>
<AnimatedCircle
cx="50"
cy="50"
fill="green"
animatedProps={animatedProps}
/>
</Svg>
<Text>{state}</Text>
<Button
title="Change Size"
onPress={() => {
size.value = withSpring(size.value === 50 ? 100 : 50);
}}
/>
<Button
title="Change State"
onPress={() => {
setState(state === 'apple' ? 'orange' : 'apple');
}}
/>
</View>
);
}
export default App;
Any help would be much appreciated 🙏
Simply move the const AnimatedCircle = Animated.createAnimatedComponent(Circle);
to outside of your function component. Because, on every render react runs your function. And since createAnimatedComponent is in your function body, it re-runs too, so it creates the component again from scratch. But you should be creating the component once.
import React, {useState, useEffect} from 'react';
import { Text, View, Button} from 'react-native';
import Animated, {
useAnimatedProps,
useSharedValue,
withSpring,
} from 'react-native-reanimated';
import Svg, {Circle} from 'react-native-svg';
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
const App = () => {
const [state, setState] = useState('apple');
const size = useSharedValue(50);
const animatedProps = useAnimatedProps(() => {
return {
r: size.value / 2,
};
});
useEffect(() => {
console.log('size.value =', size.value);
});
return (
<View style={{flex: 1}}>
<Svg height={100} width={100}>
<AnimatedCircle
cx="50"
cy="50"
fill="green"
animatedProps={animatedProps}
/>
</Svg>
<Text>{state}</Text>
<Button
title="Change Size"
onPress={() => {
size.value = withSpring(size.value === 50 ? 100 : 50);
}}
/>
<Button
title="Change State"
onPress={() => {
setState(state === 'apple' ? 'orange' : 'apple');
}}
/>
</View>
);
}