Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add transition status param to transition end listener #396

Closed
wants to merge 1 commit into from

Conversation

mvasin
Copy link
Contributor

@mvasin mvasin commented Aug 12, 2018

This is a WIP PR that addresses #389.

I started with tests (in TDD spirit). Any feedback early on is welcome!

Copy link
Collaborator

@jquense jquense left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the the right tests, I wonder tho if we should make a breaking api change here and have the order be node, status, done. Callbacks that aren't last is really unidiomatic, which is why it may be worth the break to avoid an ugly api

@mvasin
Copy link
Contributor Author

mvasin commented Aug 13, 2018

@jquense I don't mind placing the callback last. But before I'll start to reorder params, please confirm that you still believe that breaking addEndListener API is better then adding done callback to onEntering and onExiting hooks (where the callback would naturally go last).

@jquense
Copy link
Collaborator

jquense commented Aug 13, 2018

yes we do not want to add any callbacks to onEntering and onExiting, they belong properly in addEndListener

@mvasin mvasin force-pushed the add-stage-param-to-endListener branch from 512411b to a12b834 Compare August 14, 2018 07:11
@mvasin
Copy link
Contributor Author

mvasin commented Aug 14, 2018

@jquense I think I'm mostly done with the PR, please have a look.

Here's GSAP and the updated RTG showcase: https://github.com/mvasin/rtg-gsap-example
I couldn't make it work on codesandbox due to codesandbox/codesandbox-client/issues/1036, so try it locally.

this.setNextCallback(handler)

if (node) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jquense GSAP use case does not oblige to provide a DOM node; it can animate a bunch of elements by their classes or ids (and not necessary this node element among them), so I removed this check.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know that makes sense in terms of the API. GSAP can animated stuff via other means but the idea here that animation is localized to the node associated with the component (or it's children). I find the example referencing IDs confusing personally. Why use this component at all if that's the approach?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add a but unrelated that this check was added to prevent other bugs , so I'd like to keep it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole idea of this PR is letting work with multiple transitions on multiple nodes. And you wouldn't know which will transition last (you definitely don't want to hardcode it).

I use <Transition /> to transition between the routes (URLs). That's how it works for me. If you have a better idea on how to dismantle previous page and assemble next page both consisting of multiple moving elements having funky transition timing dependencies, please share.

Regarding the potential bugs, if tests pass, there are no bugs. If something will go wrong, let's discover it, write a failing test for it and fix it. Otherwise it's a road to poor and frozen code, when everybody is afraid to touch anything, like in this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jquense According to git blame, you are the one who wrote this line. If you have no idea what it stands for, let's remove it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you and am ready to put it back. But it would be a healthy practice to write a test that fails without this conditional and passes with it. Can you write one?

And I'll try to write a test for GSAP use case that fails with this conditional. :) Hopefully we'll find a middle ground.

Copy link
Contributor Author

@mvasin mvasin Aug 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added tests that ensure addEndListener is triggered even when <Transition>'s child renders nothing to the DOM. I think this behaviour is the most versatile; it works well when a child only orchestrates animations and does not render any DOM elements by itself.

It does fail when the if (node) conditional is put back.

An interesting issue arose - have a look at the failing test on Travis. If you accept that <Transition> can have a child that renders nothing to the DOM, I'll investigate it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking good, tho I don't think i understand why the "renders no node" case is important here. It looks like the example you've provided does render nodes, e.g. the page associated with the route.

Copy link
Contributor Author

@mvasin mvasin Aug 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've used () => null component that does not render to DOM and imitates a GSAP component that does timeline animation by ids/classes of other components and does not render to DOM anything on its own.

When <Transition> contains () => null (named wrapperDOMlessChild in the tests), you can see in the failing test that when exiting starts, <Transition> is not in entered state as expected, but in exited instead.

In my own project currently I do render inside <Transition>, but I'd cover this edge case because I think it's a valid.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we split that that case into another PR, and keep this focused on adding the status to the endListener? I think we are getting a bit sidetracked on a thing that wasn't the original functional addition

@mvasin
Copy link
Contributor Author

mvasin commented Aug 15, 2018

@jquense Alright, I've finished the PR with the idea that a child of <Transition> renders something to the DOM. I agree that we can finish off this DOMless child case in a separate PR if needed.

@mvasin mvasin force-pushed the add-stage-param-to-endListener branch from 2d3057d to 3de04ac Compare August 15, 2018 18:24
@mvasin
Copy link
Contributor Author

mvasin commented Aug 17, 2018

I've discovered a pattern that lets figure out the current transition status using just the current RTG API:

<Route path="/some-path">
  {({ match }) => (
    <Transition
      appear
      mountOnEnter
      unmountOnExit
      in={!!match}
      addEndListener={(node, done) => {
        const status = !!match ? 'entering' : 'exiting';
        someTransitionFunction(node, status, done);
      }}
    >
      <ChildComponent />
    </Transition>
  )}
</Route>

It turns out, if you're able to check <Transition>'s in prop inside addEndListener, you're good to go!

Here's the full working example: https://codesandbox.io/s/3yj7qyw9qm

This rises a huge question whether this PR should actually be merged or it's better not to break the API. I lean to the latter unless we'll bump into a use case where figuring out the current transition status inside the function passed to addEndListener is a problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants