Skip to content

Commit 4b9082f

Browse files
committed
update react-spring example
1 parent 60b8f81 commit 4b9082f

File tree

13 files changed

+7050
-3634
lines changed

13 files changed

+7050
-3634
lines changed

.eslintrc.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module.exports = {
1616
indent: ['error', 2],
1717
'linebreak-style': ['error', 'unix'],
1818
quotes: ['error', 'single'],
19-
semi: ['error', 'never']
19+
semi: ['error', 'never'],
20+
'react/prop-types': 0
2021
}
2122
}

.storybook/config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { configure } from '@storybook/react';
22
import '@storybook/addon-options/register';
33
import { setOptions } from '@storybook/addon-options';
4+
import { setConfig } from 'react-hot-loader';
45

56
setOptions({
67
name: 'React Animation Libraries',
@@ -17,3 +18,5 @@ function loadStories() {
1718
}
1819

1920
configure(loadStories, module);
21+
22+
setConfig({ pureSFC: true });

README.md

Lines changed: 72 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,95 @@
1-
# What's the most developer-friendly React animation library?
1+
### 🚨 Updated for 2019
22

3-
### The Goal: to replicate this animation on entering and exiting react components:
3+
# What's the most powerful and developer-friendly React animation library?
44

5-
![example animation](./src/assets/react-animation-comparison.gif)
5+
### The Task: Replicate this animation in React
66

7-
1. Initially, when it is first rendered in React, the grid should animate in, followed by the staggered animation of its children cards.
8-
2. New cards can be added individually to the cards array and should be animated in.
9-
3. Cards can be removed from the cards array and should be animated out as they leave.
10-
4. When the grid is removed from the DOM, it should wait for its children to animate out before animating itself and leaving the DOM
7+
![example animation](./src/assets/comparison.gif)
8+
9+
Here's a rundown of what should happen (it's more complex than it appears at first glance!)
10+
11+
1. When it's first rendered in React, the grid component should animate in, followed by the staggered animation of its child, a list of cards.
12+
2. New cards can be added individually to the cards array, and should be animated in.
13+
3. Individual cards can also be removed from the cards array, and should be animated out as they leave.
14+
4. When the grid component is unmounted, it should wait for its children to animate out before animating itself and leaving the DOM.
1115
5. In-progress animations should be appropriately cancelled if the enter/exit state is toggled rapidly.
12-
6. _Stretch goal_: When shuffled, the cards should smoothly transition to their new positions.
16+
6. If the cards were shuffled, they should still animate out with the expected staggered order.
1317

1418
### Why It's Hard
15-
The example sequences the "enter" and "exit" animations of both a parent and its child elements, requiring coordination between different components. Not only that, but the enter and exit animations are not simple mirrors of each other (as many libraries expect). The positions of the grid and cards should be animated with a slightly gooey-feeling elastic easing, but opacity changes should have a linear easing. The cards animating in and out are initially staggered, but adding or removing cards one-by-one should also result in a fluid animation with no delay.
1619

17-
### The Arbitrary Limit:
18-
Spend as little time as possible learning a library's API and trying to implement the animation.
20+
1. The sequenced "enter" and "exit" animations of both a parent and its child requires coordination between different components.
21+
2. The enter and exit animations are not simple mirrors of each other, as some libraries expect.
22+
3. The positions of the grid and cards should be animated with a spring (or, failing that, with an elastic easing), while opacity changes should have a linear easing
23+
4. The cards animating in and out are initially staggered, but adding or removing cards one-by-one should result in a fluid animation with no delay.
24+
5. Toggling the example rapidly should not create a broken view— cancelled animations should be cleaned up and there shouldn't be any straggler DOM elements left behind.
1925

2026
### The Results, Ordered by Preference
2127

22-
1. 🥇 **react-transition-group & animejs**
23-
24-
* Using `react-transition-group` and a JavaScript animation library ended up being my favorite technique, because it offered the flexibility to make custom, sequenced transitions.
25-
* `Animejs` is lightweight and open source, and I find the imperative API more intuitive than the typical React approach for multiple complex animations.
26-
* [my animation attempt](https://alex.holachek.com/react-animation-comparison/?selectedKind=Animation%20Examples&selectedStory=React-Transition-Group%20%2B%20animejs&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel)
27-
* [my code](https://github.com/aholachek/react-animation-comparison/blob/master/src/react-transition-group-anime-example.js)
28-
* [React transition group docs](http://reactcommunity.org/react-transition-group/)
29-
* [Anime docs](https://github.com/juliangarnier/anime)
30-
31-
2. 🥈 **react-pose**
32-
* This was the easiest example to get up and running.
33-
* The automatic FLIP animations are pretty cool (try shuffling the cards to see it in action), and the default easings made the animations look great.
34-
* I liked how the library automatically applies transitions to DOM elements for you instead of just tweening values and making you handle the style updates yourself.
35-
* The docs are good.
36-
* 🐛 **Bug** Interrupted repeat animations are implemented incorrectly (extra ghost elements are animated in if the previous animation did not fully complete). Try toggling the example multiple times fairly quickly to see what I mean.
37-
* 🐛 **Bug** Shuffling the cards will result in an out-of-order staggered exit transition.
38-
* This would have been my #1 choice were it not for the bugs.
39-
* [my animation attempt](https://alex.holachek.com/react-animation-comparison/?selectedKind=Animation%20Examples&selectedStory=Popmotion%20Pose&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel)
40-
* [my code](https://github.com/aholachek/react-animation-comparison/blob/master/src/popmotion-pose-example.js)
41-
* [Popmotion Pose docs](https://popmotion.io/pose/)
42-
43-
3. 🥉 **react-transition-group & gsap**
44-
45-
* Basically the same as the `animejs` example, just with the animation library swapped out. `GSAP` has a less permissive license and it's older and heavier than `animejs`, but it's battle-tested and powerful.
46-
* [my animation attempt](https://alex.holachek.com/react-animation-comparison/?selectedKind=Animation%20Examples&selectedStory=React-Transition-Group%20%2B%20GSAP&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel)
47-
* [my code](https://github.com/aholachek/react-animation-comparison/blob/master/src/react-transition-group-gsap-example.js)
48-
* [React transition group docs](http://reactcommunity.org/react-transition-group/)
49-
* [GSAP docs](https://greensock.com/docs)
50-
51-
4. **react-spring**
52-
53-
* This newcomer melds the powers of `react-motion` and `react-animated` into one library (and the docs have tons of cool examples).
54-
* `React-spring`'s keyframes API, which I used in my example to sequence animations makes great use of async/await but is marked as experimental in the docs.
55-
* 🐛 **Bug** There is a serious, window-crashing memory leak created when adding new cards, though this could be something I'm doing incorrectly.
56-
* I couldn't quite get the whole thing working the way I wanted to.
57-
* [my animation attempt](https://alex.holachek.com/react-animation-comparison/?selectedKind=Animation%20Examples&selectedStory=React-Spring&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel)
58-
* [my code](https://github.com/aholachek/react-animation-comparison/blob/master/src/react-spring-example.js)
59-
* [react-spring docs](https://github.com/drcmda/react-spring)
28+
1. 🥇 **react-transition-group & animejs**
29+
30+
- Using `react-transition-group` and a JavaScript animation library ended up being my favorite technique, because it offers total flexibility and control, at the cost of additional complexity.
31+
- `Animejs` is lightweight and open source, and I find the imperative API more intuitive than the typical React approach for coordinated, complex animations.
32+
- [my animation attempt](https://alex.holachek.com/react-animation-comparison/?selectedKind=Animation%20Examples&selectedStory=React-Transition-Group%20%2B%20animejs&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel)
33+
- [my code](https://github.com/aholachek/react-animation-comparison/blob/master/src/react-transition-group-anime-example.js)
34+
- [React transition group docs](http://reactcommunity.org/react-transition-group/)
35+
- [Anime docs](https://github.com/juliangarnier/anime)
36+
37+
1. 🥈 **react-spring**
38+
39+
- If you'd prefer to use a React-specific library, I recommend `react-spring`.
40+
- The library's use of the hooks API is very concise and expressive -- it took only about 70 lines of code to implement the example!
41+
- The library is in active development and supports a wide variety of use cases.
42+
- I was unable to get the cards to animate in and out in opposite directions, but that is a minor limitation.
43+
- [my animation attempt](https://alex.holachek.com/react-animation-comparison/?selectedKind=Animation%20Examples&selectedStory=React-Spring&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel)
44+
- [my code](https://github.com/aholachek/react-animation-comparison/blob/master/src/react-spring-example.js)
45+
- [react-spring docs](https://react-spring.surge.sh/)
46+
47+
1. 🥉 **react-pose**
48+
49+
- A year ago, this was my favorite option, but now the number of bugs make me hesitant to recommend it.
50+
- The good:
51+
- the library API is very user friendly.
52+
- I liked how the library automatically applies transitions to DOM elements for you instead of just tweening values and making you handle the style updates yourself.
53+
- The bad (bugs):
54+
- Interrupted repeat animations are implemented incorrectly (extra ghost elements are animated in if the previous animation did not fully complete). Try toggling the example multiple times fairly quickly to see what I mean. [Link to issue](https://github.com/Popmotion/popmotion/issues/318)
55+
- Shuffling the cards will result in an out-of-order staggered exit transition. [Link to issue](https://github.com/Popmotion/popmotion/issues/319)
56+
- (Introduced in v4): Individual card animations no longer work correctly.
57+
58+
- [my animation attempt](https://alex.holachek.com/react-animation-comparison/?selectedKind=Animation%20Examples&selectedStory=Popmotion%20Pose&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel)
59+
- [my code](https://github.com/aholachek/react-animation-comparison/blob/master/src/popmotion-pose-example.js)
60+
- [Popmotion Pose docs](https://popmotion.io/pose/)
61+
62+
4. 🥉 **react-transition-group & gsap**
63+
64+
- Basically the same as the `animejs` example, just with the animation library swapped out. `GSAP` has a less permissive license and it's older and heavier than `animejs`, but it's battle-tested and powerful.
65+
- [my animation attempt](https://alex.holachek.com/react-animation-comparison/?selectedKind=Animation%20Examples&selectedStory=React-Transition-Group%20%2B%20GSAP&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel)
66+
- [my code](https://github.com/aholachek/react-animation-comparison/blob/master/src/react-transition-group-gsap-example.js)
67+
- [React transition group docs](http://reactcommunity.org/react-transition-group/)
68+
- [GSAP docs](https://greensock.com/docs)
6069

6170
5. **react-move**
6271

63-
* A lightweight library that helps `D3` and `React` work together. It ended up not being quite flexible enough for the needs of this task, though if the demo featured more traditionally D3-like interactions it would have been great.
64-
* [my animation attempt](https://alex.holachek.com/react-animation-comparison/?selectedKind=Animation%20Examples&selectedStory=React-Move&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel)
65-
* [my code](https://github.com/aholachek/react-animation-comparison/blob/master/src/react-move-example.js)
66-
* [react-move docs](https://react-move-example.js.org/#/)
72+
- A lightweight library that helps `D3` and `React` work together. It ended up not being quite flexible enough for the needs of this task, though if the demo featured more traditionally D3-like interactions it would have been great.
73+
- [my animation attempt](https://alex.holachek.com/react-animation-comparison/?selectedKind=Animation%20Examples&selectedStory=React-Move&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel)
74+
- [my code](https://github.com/aholachek/react-animation-comparison/blob/master/src/react-move-example.js)
75+
- [react-move docs](https://react-move-example.js.org/#/)
6776

6877
6. **velocity-react**
6978

70-
* A straightforward option that got me far but then ended up tripping me up when it came time to get the nested leave animations working.
71-
* At one point, this library might have been one of the better options for animating in React, but now with `popmotion-pose`, `react-spring`, and `react-transition-group v2` there are more powerful, updated alternatives with better documentation.
72-
* [my animation attempt](https://alex.holachek.com/react-animation-comparison/?selectedKind=Animation%20Examples&selectedStory=Velocity-React&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel)
73-
* [my code](https://github.com/aholachek/react-animation-comparison/blob/master/src/velocity-react-example.js)
74-
* [velocity-react docs](https://github.com/google-fabric/velocity-react)
75-
76-
7. **react-motion**
79+
- A straightforward option that got me far but then ended up tripping me up when it came time to get the nested leave animations working.
80+
- At one point, this library might have been one of the better options for animating in React, but now with `react-spring`, `popmotion-pose`, and `react-transition-group v2` there are more powerful, updated alternatives with better documentation.
81+
- [my animation attempt](https://alex.holachek.com/react-animation-comparison/?selectedKind=Animation%20Examples&selectedStory=Velocity-React&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel)
82+
- [my code](https://github.com/aholachek/react-animation-comparison/blob/master/src/velocity-react-example.js)
83+
- [velocity-react docs](https://github.com/google-fabric/velocity-react)
7784

78-
* An hour and a half wasn't enough time for me to understand the intricacies of this physics-based animation library and to create the example animation.
79-
* [my sad animation attempt](https://alex.holachek.com/react-animation-comparison/?selectedKind=Animation%20Examples&selectedStory=React-Motion&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel)
80-
* [my code](https://github.com/aholachek/react-animation-comparison/blob/master/src/react-motion-example.js)
81-
* [react motion docs](https://github.com/chenglou/react-motion)
85+
1. **react-motion**
8286

87+
- I found this library very difficult to use when implementing the example.
88+
- [my sad animation attempt](https://alex.holachek.com/react-animation-comparison/?selectedKind=Animation%20Examples&selectedStory=React-Motion&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel)
89+
- [my code](https://github.com/aholachek/react-animation-comparison/blob/master/src/react-motion-example.js)
90+
- [react motion docs](https://github.com/chenglou/react-motion)
8391

8492
## Run the project locally
8593

8694
1. `yarn` or `npm install`
8795
2. `yarn start` or `npm start`
88-

package.json

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,21 @@
22
"name": "react-animation-comparison",
33
"version": "0.2.0",
44
"dependencies": {
5-
"@storybook/addon-options": "^3.4.3",
6-
"animejs": "^2.2.0",
5+
"animejs": "^3.0.1",
76
"d3-ease": "^1.0.3",
87
"delay": "^2.0.0",
98
"gsap": "^1.19.1",
109
"normalize.css": "^8.0.0",
11-
"popmotion": "^8.1.22",
10+
"popmotion": "^8.6.2",
1211
"prop-types": "^15.6.1",
13-
"react": "^16.3.2",
14-
"react-dom": "^16.3.2",
12+
"react": "16.8.1",
13+
"react-dom": "16.8.1",
1514
"react-motion": "^0.5.0",
16-
"react-move": "^2.7.0",
17-
"react-pose": "^3.1.0",
18-
"react-scripts": "1.1.4",
19-
"react-spring": "^5.1.1",
20-
"react-transition-group": "^2.3.1",
21-
"storybook-readme": "^2.0.2",
15+
"react-move": "^5.1.0",
16+
"react-pose": "^4.0.5",
17+
"react-scripts": "2.1.3",
18+
"react-spring": "^8.0.5",
19+
"react-transition-group": "^2.5.2",
2220
"velocity-animate": "^1.5.0",
2321
"velocity-react": "^1.4.1"
2422
},
@@ -29,10 +27,15 @@
2927
"deploy-storybook": "storybook-to-ghpages"
3028
},
3129
"devDependencies": {
32-
"@storybook/addon-actions": "^3.4.3",
33-
"@storybook/addon-links": "^3.4.3",
34-
"@storybook/react": "^3.4.3",
30+
"@babel/core": "^7.2.2",
31+
"@storybook/addon-actions": "^4.1.6",
32+
"@storybook/addon-links": "^4.1.6",
33+
"@storybook/addon-options": "^4.1.11",
34+
"@storybook/react": "^4.1.11",
3535
"@storybook/storybook-deployer": "^2.3.0",
36-
"prettier": "1.14.2"
36+
"babel-loader": "^8.0.5",
37+
"prettier": "1.14.2",
38+
"react-hot-loader": "^4.6.3",
39+
"storybook-readme": "^4.0.5"
3740
}
3841
}

src/assets/comparison.gif

707 KB
Loading
-603 KB
Binary file not shown.

src/common/container.js

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import React, { Component } from "react"
2-
import shuffle from "./shuffle"
1+
import React, { Component } from 'react'
2+
import shuffle from './shuffle'
33

44
export default class Container extends Component {
55
state = {
@@ -22,15 +22,17 @@ export default class Container extends Component {
2222
}
2323

2424
removeItem = itemToRemove => {
25-
const items = this.state.items.filter(item => item !== itemToRemove)
26-
this.setState({ items })
25+
this.setState(({ items }) => ({
26+
items: items.filter(item => item !== itemToRemove)
27+
}))
2728
}
2829

2930
shuffleItems = () => {
3031
this.setState({ items: [...shuffle(this.state.items)] })
3132
}
3233

3334
render() {
35+
const { animationComponent: AnimationComponent } = this.props
3436
return (
3537
<div className="p-4">
3638
<div>
@@ -53,12 +55,12 @@ export default class Container extends Component {
5355
)}
5456
</div>
5557
<div>
56-
{this.props.render({
57-
items: this.state.items,
58-
visible: this.state.visible,
59-
addItem: this.addItem,
60-
removeItem: this.removeItem
61-
})}
58+
<AnimationComponent
59+
items={this.state.items}
60+
visible={this.state.visible}
61+
addItem={this.addItem}
62+
removeItem={this.removeItem}
63+
/>
6264
</div>
6365
</div>
6466
)

src/popmotion-pose-example.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const Grid = posed.ul(GridProps)
4141

4242
const itemProps = {
4343
preEnter: {
44-
y: -50,
44+
y: -30,
4545
opacity: 0,
4646
transition: { type: 'spring' }
4747
},
@@ -51,7 +51,7 @@ const itemProps = {
5151
transition: { type: 'spring' }
5252
},
5353
exit: {
54-
y: -50,
54+
y: -30,
5555
opacity: 0,
5656
transition: { type: 'spring' }
5757
}

src/react-move-example.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,4 @@ class TransitionGrid extends Component {
115115
}
116116
}
117117

118-
export default props => <TransitionGrid {...props} />
118+
export default TransitionGrid

0 commit comments

Comments
 (0)