While trying to make an expandable component where when tapped, it expands to a dynamic height with animation, I ran into this weird behavior where a useRef object would not update.
const contentHeight = useRef(0)
const [expand, setExpand] = useState(false)
const eleHeight = useSharedValue(0)
const animatedStyle = useAnimatedStyle(() => {
console.log(contentHeight.current)
return ({
height: withSpring(eleHeight.value)
})})
return <View>
<TouchableOpacity onPress={()=>setExpand(!expand)}>
<Text>{title}</Text>
<Animated.View
style=[animatedStyle]
onLayout={getContentHeight}
>
{expand && <Text>unknown content</Text> }
</Animated.View>
</TouchableOpacity>
</View>
Inside getContentHeight:
const getContentHeight = (event) => {
const height = event.nativeEvent.layout.height
console.log('-------onlayout')
if (contentHeight.current === 0) {
console.log('CH is zero now', contentHeight.current, height)
contentHeight.current = height;
eleHeight.value = height
console.log('updated to ', contentHeight.current, height)
}
};
The output is always
console: CH is zero now 0 30
console: updated to 0 30
(around 30 because withSpring)
useRef value does not change when I set contentHeight.current = height and height is not 0, which is strange.
I also struggled with custom layout animation using react-native-reanimated if anyone wanna give me a hand.
EDIT: Some major findings and clarifications after hours of debugging...
The code I posted is not the full code and does not achieve what I want it to do, but it does allow you to recreate the problem.
onLayout gets affected by animatedStyle! I thought it was the other way around initially. During initial rendering, the onLayout gets called with a height of 30. The actual height is 0, but because
eleHeightstarts as 0, the padding and margin are each 15, thus the value is 30. (I didn't include those styling in the code).My use of
contentHeight.currentinsideuseAnimatedStyleis what caused the behavior of it not updating, but I don't know why.