nandorojo/moti

AnimatePresent not unmounts component when using 'worklet'

Closed this issue · 14 comments

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

Component remains in tree and not umounted after exit.

Expected Behavior

Component should be unmounted after exit

Steps To Reproduce

  1. Use exit prop with worklet

Versions

- Moti: 0.18.0
- Reanimated: 2.8.0
- React Native: 0.68.2
- Expo: 45.0.4

Screenshots

No response

Reproduction

function MyComponent() {
  const forward = true

  return (
    <AnimatePresence custom={forward} initial={false}>
      <MotiView
        key={index}
        style={[StyleSheet.absoluteFill, styles.content]}
        from={forward ? ANIMATE_RT : ANIMATE_LT_STACK}
        animate={{ translateX: 0 }}
        // exit={{ opacity: 0 }} // <- with this component unmounts
        exit={(custom) => {
          'worklet'
          // With 'worklet' exit components still exist in tree and proceed weird animations
          return custom ? ANIMATE_LT_STACK : ANIMATE_RT
        }}
        transition={TRANSITION}
      >
        {arr[index]}
      </MotiView>
    </AnimatePresence>
  )
}

const ANIMATE_RT = {
  translateX: WIDTH,
  zIndex: 10,
}
const ANIMATE_LT_STACK = { translateX: -WIDTH, zIndex: 5 }
const ANIMATE_LT = { translateX: -WIDTH }
const TRANSITION: TransitionConfig = {
  type: 'timing',
  duration: 2000,
  easing: Easing.out(Easing.cubic),
}

const styles = StyleSheet.create({
  content: {
    overflow: 'hidden',
  },
})

what happens if you define these objects inside of the worklet?

Just now tried like this:

exit={(custom) => {
  'worklet'
  return custom
    ? { translateX: -WIDTH, zIndex: 5 }
    : {
        translateX: WIDTH,
        zIndex: 10,
      }
}}

Still the same issue

can you take out zIndex and apply that directly to style? that can’t be animated

Thanks a lot! Without zIndex everything works.
Maybe, it can be useful to add some warning in development when using wrong props.

yeah there is a list of invalid props for exits, would be great if you could send a PR to add zIndex. otherwise i’ll do it next time i have time

const disabledExitStyles = {

nvm, i did it here 6226c3e

Hm.. With opacity i have the same problem when component not unmounts:

exit={(custom) => {
  'worklet'
  return custom
    ? { translateX: -WIDTH }
    : {
        translateX: WIDTH,
        opacity: 0, // <- remove opacity and component will unmount
      }
}}

make sure that you set the value it should animate from in other places. unlike framer motion, moti does not set default values. so you need to set opacity to 1 in animate or from if you want it to transition out to 0

I tried:

<MotiView
  key={index}
  style={[StyleSheet.absoluteFill, styles.content, { zIndex: index }]}
  from={forward ? ANIMATE_RT : ANIMATE_LT_STACK}
  animate={ANIMATE_IN}
  exit={(custom) => {
    'worklet'
    return custom ? ANIMATE_LT_STACK : ANIMATE_RT
  }}
  transition={TRANSITION}
>
  {arr[index]}
</MotiView>

const ANIMATE_RT = { translateX: WIDTH, opacity: 1 }
const ANIMATE_LT_STACK = { translateX: -WIDTH / 4, opacity: 0.5 } // <- remove opacity from here and it will work
const ANIMATE_LT = { translateX: -WIDTH, opacity: 1 }
const ANIMATE_IN = { translateX: 0, opacity: 1 }

weird. what’s the transition

oddly I can't reproduce this. could you try making an expo snack maybe?

I'm having the same issue and I tried making an expo snack with the same code and moti version (0.18) and somehow it works fine on the snack (https://snack.expo.dev/9X0_pM9sS) but not in a dev environment

chances are, there's some other reason. is it an expensive component? AnimatePresence should only be used for simple animations usually, not for deeply-nested components