How to do animations with React and Immutable.js?

437 views Asked by At

I have a carousel that takes a state of {pages: [...], currentPage: 0}. If I set currentPage = 1 I want the carousel to slide left. The same thing should happen if I increase the number again, and it should slide right I decrease it.

I can't work out how this should be done with immutable data. The animation shouldn't be represented in the state object (should it?), but storing a property on the React component removes its "pure" functional nature.

What's the best way to approach this problem?

1

There are 1 answers

2
aaronstacy On

Just show me an example

This doesn't use Immutable.js, but the current property is just a number, which is immutable in JS, so in some regards it's the same idea:

http://jsbin.com/ligejacolo/edit?js,output

IMO the best option is ReactCSSTransitionGroup

+1 for the unnecessarily snarky reference to ReactCSSTransitionGroup in the comments, if you can use that.

After that, let the browser manage state via CSS transitions

I would store the pages and currentPage as props, regardless of whether the values are Immutable.js instances (props are a stateful part of your UI, just like state, don't let the name fool you!). When they're stored as props, it provides a useful API to the users of your component.

If you're using CSS transitions then at any given moment you should be able to render the markup and classes based on this information.

For example, given the (over-simplified markup):

<div class=container>
  <!-- set the class to something like "inner pane2" to go to the second pane -->
  <div class=inner>
    <span class=pane>...</span>
    <span class=pane>...</span>
    <span class=pane>...</span>
  </div>
</div>

And some CSS like:

.container {
  position: relative;
}

.inner {
  position: absolute;
  left: 0;
  transition: left 0.3s ease-in-out;
}

.pane {
  width: 100px;
}

.inner.pane2 {
  left: -100px;
}

.inner.pane3 {
  left: -200px;
}

The browser takes care of mid-transition changes to the properties.

Often times you'll need to know when the animation is done, which you can accomplish with a transitionend listener and isAnimating flag (which I would store in the state, not the props). Set isAnimating when currentPage changes and clear it on transitionend.

You'll also often need to know which direction you're transitioning, which you can accomplish with a previousPage prop.

Finally, if you're just using JavaScript

Keep a reference to the current transition in the state (possibly the jQuery selection used to start the animation, if that's what you're using). When the transition is done, remove the reference. If the currentPage changes mid-transition, call .stop() on the selection (or whatever API you're using).