nandorojo / moti

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

AnimatePresence + Hermes doesn't work #214

Closed davidnum closed 1 year ago

davidnum commented 1 year ago

Is there an existing issue for this?

Current Behavior

MotiView stuck/freeze appearing animation when wrapped in AnimatedPresence with exitBeforeEnter prop. Patch from https://github.com/nandorojo/moti/issues/195 and changes in https://github.com/nandorojo/moti/pull/200 does not fix this bug.

Bug not exists in moti@0.17.1

Steps To Reproduce

  1. Only happens when MotiView has multiple animated properties:
    <MotiView
    from={{ opacity: 0,   scale: 0.9 }}
    animate={{ opacity: 1, scale: 1 }}
    exit={{ opacity: 0, scale: 0.9 }}
    />
  2. Wrap MotiView into AnimatePresence with exitBeforeEnter prop
  3. Enable hermes in Podfile

Versions

- Moti: 0.18.0
- Reanimated: 2.9.1
- React Native: 0.67.4 - 0.69

Screenshots

Current Behavior:

https://user-images.githubusercontent.com/7981854/180895644-b2298203-076c-4f2c-9141-57cd4ebf495c.mov

Expected Behavior:

https://user-images.githubusercontent.com/7981854/180895655-e797b750-375e-4837-835b-771cd2808836.mov

Reproduction

https://github.com/davidnum/motibug

nandorojo commented 1 year ago

Interesting, so this works without Hermes for you? What version of Hermes?

nandorojo commented 1 year ago

And you're saying that this only happens with Moti 0.18, but not 0.17?

davidnum commented 1 year ago

Interesting, so this works without Hermes for you? What version of Hermes?

Expected behavior video recorded without enabling hermes. Hermes versions: 0.10, 0.11.

davidnum commented 1 year ago

And you're saying that this only happens with Moti 0.18, but not 0.17?

Yeah, on 0.17.1 it works as expected.

nandorojo commented 1 year ago

I see. It looks like this would be caused by the Framer Motion upgrade in moti@0.18.0:

Could you try adding this to your package.json?

{
  "resolutions": { "framer-motion": "3.9.1" }
}

And then run yarn install --force

davidnum commented 1 year ago

I see. It looks like this would be caused by the Framer Motion upgrade in moti@0.18.0:

Could you try adding this to your package.json?

{
  "resolutions": { "framer-motion": "3.9.1" }
}

And then run yarn install --force

Didn't help :(

nandorojo commented 1 year ago

🧐

i can’t see anything else in the change log that would be unique to 0.18 causing problems…what’s the full code?

davidnum commented 1 year ago

🧐

i can’t see anything else in the change log that would be unique to 0.18 causing problems…what’s the full code?

https://github.com/davidnum/motibug

faz919 commented 1 year ago

Having the same issue on Android (not iOS) on moti 0.18

nandorojo commented 1 year ago

@faz919 and disabling hermes solves it?

faz919 commented 1 year ago

Not sure but downgrading to moti 0.17.1 fixed the issue.

nandorojo commented 1 year ago

did you try the yarn resolution?

faz919 commented 1 year ago

nah. Was in a time crunch and had to do fastest possible solution

davidnum commented 1 year ago

@nandorojo hi, any news?

midrizi commented 1 year ago

@nandorojo Resolution doesn't seem to be working.

{ "resolutions": { "framer-motion": "3.9.1" } }

Another issue that I have is that onExitComplete never seems to fire on 0.18.0 whenever I provide two types of animations {opacity: 0, translateY: 50} , however it does work with one value {opacity: 0}.

Seems to work properly on lower versions. So for now I'm downgrading to 0.17.1 until there is a fix.

Edit:

In 0.17.1 MotiPressable onPress event seems to be broken, <Pressable /> from react-native works, not sure what's going on there.

Just noticed #143 #179.

nandorojo commented 1 year ago

Thanks for the update. I'll keep looking into it soon when I have some time. I'm convinced it's a dependency-related issue.

Jemaz commented 1 year ago

Also to add, using sequences with the useDynamicAnimation hook is broken with Hermes enabled.

For example, the below will not work with the latest Expo (SDK 46) and Hermes enabled (was working before when Hermes was disabled):

import { Pressable } from "native-base";
import { useDynamicAnimation } from "moti";
const animation = useDynamicAnimation(() => {
    return {
      scale: 1
    }
  })
<Pressable onPress={() => {
  animation.animateTo({
    scale: [1.2, { value: 1, type: 'spring' }]
  })
}}>
  <MotiView state={animation}>
    <Text>Placeholder...</Text>
  </MotiView>
</Pressable>

I think you are right @nandorojo this being a dependency-related and it might not be scoped to just using AnimatePresence.

nandorojo commented 1 year ago

Oof Hermes is killing me here! Haha

Jemaz commented 1 year ago

I feel very sorry for you now, haha 🤣

Just a heads up, I've updated the code with the one that actually throws the error, and throws this: image

Also, for those strolling here and was stuck like me, what I wanted to achieve it to animate the sequence, I think Hermes with different JS support language features doesn't allow the previous syntax or it could be a react-reanimated issue. Anyways I fixed my issue by tweaking the syntax like this:

import { Pressable } from "native-base";
import { useDynamicAnimation } from "moti";
const animation = useDynamicAnimation(() => {
    return {
      scale: 1
    }
  })
<Pressable onPress={() => {
 animation.animateTo({
              scale: [
                { value: 1.2, type: 'spring', duration: 500 },
                { value: 1, type: 'spring' }
              ]
            })
}}>
  <MotiView state={animation}>
    <Text>Placeholder...</Text>
  </MotiView>
</Pressable>
RSchneider94 commented 1 year ago

Having the same issue here, unfortunately 😢 .. and for me, trying to downgrade to 0.17.1, is not a possible workaround, because I'm already using the React 18 and with that the children is missing

semvgelooven commented 1 year ago

I'm experiencing the same issue as well and not using hermes, downgrading to 0.17.1 seems to work for me. I'm using:

With Moti 0.21.0 this does not work:

<AnimatePresence exitBeforeEnter>
  <MotiView
    key={item.id}
    from={{
      opacity: 0,
      transform: [{ translateY: -10 }],
    }}
    animate={{
      opacity: 1,
      transform: [{ translateY: 0 }],
    }}
    exit={{
      opacity: 0,
      transform: [{ translateY: -10 }],
    }}
    transition={{ type: "timing", duration: 400, delay: 50 }}
    >
    <Text>{item.title}</Text>
  </MotiView>
</AnimatePresence>

item is set via a prop in another component. Code above does work on Moti 0.17.1

nandorojo commented 1 year ago

could you do me a favor and runyarn why framer-motion before & after changing moti versions? i’m very curious if framer versions is the cause. I don’t see what else it could be.

semvgelooven commented 1 year ago

Before:

=> Found "framer-motion@3.10.6"
info Reasons this module exists
   - "moti#@motify#core" depends on it
   - Hoisted from "moti#@motify#core#framer-motion"
info Disk size without dependencies: "4.82MB"
info Disk size with unique dependencies: "6.58MB"
info Disk size with transitive dependencies: "6.58MB"
info Number of shared dependencies: 5

After:

=> Found "framer-motion@6.5.1"
info Reasons this module exists
   - "moti" depends on it
   - Hoisted from "moti#framer-motion"
info Disk size without dependencies: "2.7MB"
info Disk size with unique dependencies: "5.5MB"
info Disk size with transitive dependencies: "6.57MB"
info Number of shared dependencies: 6
nandorojo commented 1 year ago

Okay so this must be it. Does the newest version work if you add a yarn resolution to framer 3.10.6?

semvgelooven commented 1 year ago

I've added a resolution to my package.json for framer-motion:

"resolutions": {
    "framer-motion": "3.10.6"
  }

Then installed the latest Moti and ran yarn why framer-motion which results in version 3.10.6. Build and ran my app again but the problem still exists.

Reverted back to 0.17.1, build and ran my app and then it works as intended. When using 0.17.1 I do see that <AnimatePresence> is underlined in my IDE and when hovered refers to import { Frame, AnimatePresence } from 'framer' but is imported like so: import { AnimatePresence, MotiView } from "moti".

nandorojo commented 1 year ago

Hm, okay. Still a bit peculiar to me. Will try to figure it out when I can.

nandorojo commented 1 year ago

Alright, I'm deeply investigating. I've spent hours diffing lock files. Here are some findings.

Here is what it looks like to install it:

info Direct dependencies
└─ moti@0.18.0
info All dependencies
├─ @motify/components@0.18.0
├─ @motionone/animation@10.15.1
├─ @motionone/dom@10.12.0
├─ @motionone/easing@10.15.1
├─ @motionone/generators@10.15.1
├─ framer-motion@6.5.1
├─ moti@0.18.0
└─ popmotion@11.0.3

I ran a diff of all files from moti and went one-by-one to see what the cause could be (yes really).

By pulling useMotify from 0.170.18, I found that it started working again. This meant that something in the 0.18 change in the worklets made a difference. In that update, I improved performance by changing .forEach loops to use for (const key of) loops. I'm wondering if Hermes didn't like that...

I tried changing for (const key in mergedStyles) to Object.keys(mergedStyles).forEach(key => and...that did it 🧐.

So, I guess I have to refactor that back. This whole coding thing may not be for me lol

nandorojo commented 1 year ago

Moti finally works with Hermes in version 0.22. Please upgrade and let me know if it works for you. Appreciate your patience.