I'm experimenting with react-spring
trying to apply animations on a list of components on mount/unmount using the <Transition>
component. The animation happens as expected on mount but doesn't happen at all on unmount–the removed components appear to immediately unmount without animation.
I suspect I'm misunderstanding how keys
work as it seems to be the only thing that differs in my code versus the examples—I'm using the id
property from each object an array. My assumption is that it's the same as React's built-in key
used for lists of components, just passed all at once. I've tried passing the data array using Transition
's items
argument and setting key
to be a function, but it just malfunctions in a different way.
I set up a simple demo here, where I made a list and set a timeout to remove the first item after 3 seconds—here's the code:
import React, { Component } from "react";
import { animated, config, Transition } from "react-spring";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
items: [
{
id: 1,
text: "This is item 1"
},
{
id: 2,
text: "This is item 2"
},
{
id: 3,
text: "This is item 3"
}
]
};
}
componentDidMount() {
const { items } = this.state;
setTimeout(() => {
this.setState({
items: items.slice(1)
});
}, 3000);
}
render() {
const { items } = this.state;
return (
<div className="App">
<ul>
<Transition
native
keys={items.map(item => item.id)}
config={config.slow}
from={{ opacity: 0 }}
to={{ opacity: 1 }}
>
{items.map(item => styles => {
return <animated.li style={styles}>{item.text}</animated.li>;
})}
</Transition>
</ul>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
And I've it running on a CodeSandbox here: https://codesandbox.io/s/r5n8v3x85q
Am I missing something?
I got it working with the following code. You were missing the "leave" property on the Transition component. Also you can pass in "transition" for the properties in the Transition component, it will give you much nicer looking animations.
import React, { Component } from "react";
import { animated, config, Transition } from "react-spring";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
items: [
{
id: 1,
text: "This is item 1"
},
{
id: 2,
text: "This is item 2"
},
{
id: 3,
text: "This is item 3"
}
]
};
}
componentDidMount() {
const { items } = this.state;
setTimeout(() => {
this.setState({
items: items.slice(1)
});
}, 3000);
}
render() {
const { items } = this.state;
return (
<div className="App">
<button onClick={() => this.setState({items: []})}>Remove List items</button>
<ul>
<Transition
native
keys={items.map(item => item.id)}
config={config.slow}
from={{ opacity: 0, transition: "opacity .25s ease" }}
to={{ opacity: 1, transition: "opacity .25s ease" }}
leave={{ opacity: 0, transition: "opacity .25s ease" }}
>
{items.map(item => styles => {
return <animated.li style={styles}>{item.text}</animated.li>;
})}
</Transition>
</ul>
</div>
);
}
}