useRef.current does not work inside a onLayout callback due to being accessed in useAnimatedStyle

62 views Asked by At

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...

  1. 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.

  2. 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 eleHeight starts as 0, the padding and margin are each 15, thus the value is 30. (I didn't include those styling in the code).

  3. My use of contentHeight.current inside useAnimatedStyle is what caused the behavior of it not updating, but I don't know why.

0

There are 0 answers