nandorojo / moti

🐼 The React Native (+ Web) animation library, powered by Reanimated 3.
https://moti.fyi
MIT License
4.01k stars 127 forks source link

AnimatePresent not unmounts component when using 'worklet' #202

Closed mc-petry closed 2 years ago

mc-petry commented 2 years ago

Is there an existing issue for this?

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',
  },
})
nandorojo commented 2 years ago

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

mc-petry commented 2 years ago

Just now tried like this:

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

Still the same issue

nandorojo commented 2 years ago

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

mc-petry commented 2 years ago

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

nandorojo commented 2 years ago

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

nandorojo commented 2 years ago

https://github.com/nandorojo/moti/blob/bd0e37d6319ed06c4d9926a66a3411bab090a980/packages/core/src/use-map-animate-to-style.ts#L314

nandorojo commented 2 years ago

nvm, i did it here https://github.com/nandorojo/moti/commit/6226c3e76f47077d2f634fe6355076471989dc85

mc-petry commented 2 years ago

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
      }
}}
nandorojo commented 2 years ago

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

mc-petry commented 2 years ago

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 }
nandorojo commented 2 years ago

weird. what’s the transition

nandorojo commented 2 years ago

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

faz919 commented 2 years ago

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

nandorojo commented 2 years ago

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