UPDATED
Animations stopped cannot be restarted so you should not memoize them but recreate at each render (function call)
Following your approach:
const [isPaused, setPause] = useState(true)
const figureScale = useRef(new Animated.Value(1)).current
useEffect(()=> isPaused ? anim.stop() : anim.start() , [isPaused, anim])
const anim = Animated.loop(
Animated.sequence([
Animated.timing(figureScale, { toValue: 2, duration: 500, useNativeDriver: true}),
Animated.timing(figureScale, { toValue: 1, duration: 500, useNativeDriver: true})
])
)
Still there is a problem because even though we keep the Animated.Value in the ref, the sequence restart using the first Animated.timing (expanding) also when we stop during the second one (decreasing).
I tried to solve with interpolation with no success but a solution I found it's to add a listener to the Animated.Value and save the expanding/decreasing state in a variable (state or closure).
( https://reactnative.dev/docs/animatedvalue#addlistener )
Using the state (extra rendering):
const [isGrowing, setGrowing] = useState(true)
figureScale.addListener(({value})=>{
if(isGrowing && value==2) {setGrowing(false)}
if(!isGrowing && value==1) {setGrowing(true)}
})
Using a closure:
const isGrowing = React.useMemo(() =>
{
// static variable
let _isGrowing = true
// returned function
return function(growing){
if(growing===1) _isGrowing = true
if(growing===-1) _isGrowing = false
return _isGrowing
}
}, [] )
figureScale.addListener(({value})=>{
if(isGrowing() && value==2) {isGrowing(-1)}
if(!isGrowing() && value==1) {isGrowing(1)}
})
Finally we can choose the order of the animations inside the sequence following the expanding/decreasing stop:
Using the state:
const anim = Animated.loop(
Animated.sequence([
Animated.timing(figureScale, { toValue: isGrowing ?2:1, duration: 500, useNativeDriver: true}),
Animated.timing(figureScale, { toValue: isGrowing ?1:2, duration: 500, useNativeDriver: true})
])
)
Using a closure:
const anim = Animated.loop(
Animated.sequence([
Animated.timing(figureScale, { toValue: isGrowing() ?2:1, duration: 500, useNativeDriver: true}),
Animated.timing(figureScale, { toValue: isGrowing() ?1:2, duration: 500, useNativeDriver: true})
])
)
Working example here: https://snack.expo.dev/@laxandrea/start-stop-animations