leptos-rs / leptos

Build fast web applications with Rust.
https://leptos.dev
MIT License
16.07k stars 631 forks source link

AnimatedRoutes causes outlet to not transition on first click #1754

Open akarras opened 1 year ago

akarras commented 1 year ago

Describe the bug A clear and concise description of what the bug is.

Leptos Dependencies Currently based off latest main.

leptos = { git = "https://github.com/leptos-rs/leptos.git", default-features = false, features = [
  "serde",
  "nightly"
] }
leptos_axum = { git = "https://github.com/leptos-rs/leptos.git" }
leptos_router = { git = "https://github.com/leptos-rs/leptos.git", default-features = false, features = ["nightly"] }
leptos_meta = { git = "https://github.com/leptos-rs/leptos.git", default-features = false, features = ["nightly"] }

To Reproduce gist with minimum repro

  1. Navigate to animated outlet inside the gist
  2. Choose a page. Observe outlet doesn't render correctly but URL gets updated
  3. Choose 2nd page, observe outlet now succeeds

Expected behavior AnimatedOutlets to render within a AnimatedRoute

Additional context Within my app with Outlets containing resources I've seen a slightly different behavior where the outlet lags behind by a page every navigation. Haven't been able to repro separately though.

gbj commented 1 year ago

I'm able to reproduce this but only if I don't add any animations. If I add CSS animations (see below for example), it does actually work with the code in the gist.

AnimatedRoutes and AnimatedOutlet are driven by state machines that update on the animationend event, so they do require CSS animations actually to be running. It's definitely possible this is brittle and leading to the problems you are experiencing.

I'd be very happy for help in pinning down the actual cause here. This was a feature request I worked on and added but not something I actually use, and I have pretty limited experience with animations in general.

Example CSS I used: (I switched the classes passed to the AnimatedRoutes and AnimatedOutlet components to fadeIn and fadeOut, since I already had these animations available)


.fadeIn {
  animation: 0.5s fadeIn forwards;
}

.fadeOut {
  animation: 0.5s fadeOut forwards;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

@keyframes fadeOut {
  from {
    opacity: 1;
  }

  to {
    opacity: 0;
  }
}
akarras commented 1 year ago

I probably should've mentioned before, but this was working prior to updating to 0.5.0. I do provide animations for each route, I don't think that's necessarily the issue but I might have an idea now that bring up the brittle state machines, especially given the changes that happened with 0.5.

I wouldn't consider myself an expert with CSS animations either, but I like shiny toys which is probably how I end up with bugs like this😄

Here's my theory:

  .route-out {
    animation-name: fade-out;
    animation-duration: var(--page-transition-time);
    animation-iteration-count: 1;
    animation-timing-function: linear;
  }

  .route-in {
    animation-name: fade-in;
    animation-duration: var(--page-transition-time);
    animation-iteration-count: 1;
    animation-timing-function: linear;
  }

  .route-out>* {
    animation-name: slide-out;
    animation-duration: var(--page-transition-time);
    animation-iteration-count: 1;
    animation-timing-function: linear;
  }

  .route-in>* {
    animation-name: slide-in;
    animation-duration: var(--page-transition-time);
    animation-iteration-count: 1;
    animation-timing-function: linear;
  }

Note that the animation applies to the children of the class as well-

<AnimatedOutlet outro="route-out" intro="route-in"/>
<AnimatedRoutes outro="route-out" intro="route-in" outro_back="route-out-back" intro_back="route-in-back">

and I am reusing the class for routes and outlet to really make the page shake and make people vomit

So here's my thought- is the state machine for the AnimatedOutlet getting triggered by the AnimatedRoutes finishing the same animation it's trying to run? With more things in the reactive runtime being run the next frame in 0.5.0 this would make sense to me why this is suddenly an issue.

gbj commented 1 year ago

Could you share the rest of the relevant CSS? I'm not able to reproduce the example because of the missing animations and CSS variables in what you pasted above.

akarras commented 1 year ago

The CSS is just from the MRE I posted in the original. I can throw it into a separate repo if that's easier to pull down and clone later tonight.

edit: I do think this is a pretty stupid edge case, don't waste too much energy on this! 😄

gbj commented 1 year ago

Oh sorry, I somehow missed the second file in the gist!

gbj commented 1 year ago

@akarras I'm pretty sure the linked PR breaks a bunch of other things — for example, the router example in the repo seems broken now! — but maybe it points in the right direction if you want to explore at all... There's something about the AnimationState transitions that seems off to me, and which is causing the combination of AnimatedRoutes and AnimatedOutlet to lag behind by one route, for a single navigation, specifically if you navigate to the sibling of the one with all the params. (If you navigate to /animatedoutlet/3 via the link, navigation to its siblings works fine.)

lazyky commented 9 months ago

It looks like there is the same bug in the example router

Reproduce the bug

trunk serve --open

  1. Click 'About'
  2. Click 'Contacts'
  3. Click 'Bill Smith'
  4. The URL updated but page doesn't render correctly ac2d471b2c669af7acc1b12c65d46df