mirror of
https://github.com/reactjs/react.dev.git
synced 2026-02-26 17:35:10 +00:00
Update to the animation documentation for ReactTransitionGroup to clear the air on where one can use it. If someone tries to use it off of React.addons.ReactTransitionGroup, which is undefined, instead of its real location, React.addons.TransitionGroup, they get a vague error about being unable to set defaultProps of undefined in the React createElement body.
185 lines
7.5 KiB
Markdown
185 lines
7.5 KiB
Markdown
---
|
|
id: animation
|
|
title: Animation
|
|
permalink: animation.html
|
|
prev: addons.html
|
|
next: two-way-binding-helpers.html
|
|
---
|
|
|
|
React provides a `ReactTransitionGroup` addon component as a low-level API for animation, and a `ReactCSSTransitionGroup` for easily implementing basic CSS animations and transitions.
|
|
|
|
## High-level API: `ReactCSSTransitionGroup`
|
|
|
|
`ReactCSSTransitionGroup` is based on `ReactTransitionGroup` and is an easy way to perform CSS transitions and animations when a React component enters or leaves the DOM. It's inspired by the excellent [ng-animate](http://www.nganimate.org/) library.
|
|
|
|
### Getting Started
|
|
|
|
`ReactCSSTransitionGroup` is the interface to `ReactTransitions`. This is a simple element that wraps all of the components you are interested in animating. Here's an example where we fade list items in and out.
|
|
|
|
```javascript{28-30}
|
|
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
|
|
|
|
var TodoList = React.createClass({
|
|
getInitialState: function() {
|
|
return {items: ['hello', 'world', 'click', 'me']};
|
|
},
|
|
handleAdd: function() {
|
|
var newItems =
|
|
this.state.items.concat([prompt('Enter some text')]);
|
|
this.setState({items: newItems});
|
|
},
|
|
handleRemove: function(i) {
|
|
var newItems = this.state.items;
|
|
newItems.splice(i, 1);
|
|
this.setState({items: newItems});
|
|
},
|
|
render: function() {
|
|
var items = this.state.items.map(function(item, i) {
|
|
return (
|
|
<div key={item} onClick={this.handleRemove.bind(this, i)}>
|
|
{item}
|
|
</div>
|
|
);
|
|
}.bind(this));
|
|
return (
|
|
<div>
|
|
<button onClick={this.handleAdd}>Add Item</button>
|
|
<ReactCSSTransitionGroup transitionName="example">
|
|
{items}
|
|
</ReactCSSTransitionGroup>
|
|
</div>
|
|
);
|
|
}
|
|
});
|
|
```
|
|
> Note:
|
|
>
|
|
> You must provide [the `key` attribute](/react/docs/multiple-components.html#dynamic-children) for all children of `ReactCSSTransitionGroup`, even if rendering a single item. This is how React will determine which children have entered, left, or stayed.
|
|
|
|
In this component, when a new item is added to `ReactCSSTransitionGroup` it will get the `example-enter` CSS class and the `example-enter-active` CSS class added in the next tick. This is a convention based on the `transitionName` prop.
|
|
|
|
You can use these classes to trigger a CSS animation or transition. For example, try adding this CSS and adding a new list item:
|
|
|
|
```css
|
|
.example-enter {
|
|
opacity: 0.01;
|
|
transition: opacity .5s ease-in;
|
|
}
|
|
|
|
.example-enter.example-enter-active {
|
|
opacity: 1;
|
|
}
|
|
```
|
|
|
|
You'll notice that when you try to remove an item `ReactCSSTransitionGroup` keeps it in the DOM. If you're using an unminified build of React with add-ons you'll see a warning that React was expecting an animation or transition to occur. That's because `ReactCSSTransitionGroup` keeps your DOM elements on the page until the animation completes. Try adding this CSS:
|
|
|
|
```css
|
|
.example-leave {
|
|
opacity: 1;
|
|
transition: opacity .5s ease-in;
|
|
}
|
|
|
|
.example-leave.example-leave-active {
|
|
opacity: 0.01;
|
|
}
|
|
```
|
|
|
|
### Animation Group Must Be Mounted To Work
|
|
|
|
In order for it to apply transitions to its children, the `ReactCSSTransitionGroup` must already be mounted in the DOM. The example below would not work, because the `ReactCSSTransitionGroup` is being mounted along with the new item, instead of the new item being mounted within it. Compare this to the [Getting Started](#getting-started) section above to see the difference.
|
|
|
|
```javascript{12-15}
|
|
render: function() {
|
|
var items = this.state.items.map(function(item, i) {
|
|
return (
|
|
<div key={item} onClick={this.handleRemove.bind(this, i)}>
|
|
<ReactCSSTransitionGroup transitionName="example">
|
|
{item}
|
|
</ReactCSSTransitionGroup>
|
|
</div>
|
|
);
|
|
}, this);
|
|
return (
|
|
<div>
|
|
<button onClick={this.handleAdd}>Add Item</button>
|
|
{items}
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
### Animating One or Zero Items
|
|
|
|
Although in the example above we rendered a list of items into `ReactCSSTransitionGroup`, the children of `ReactCSSTransitionGroup` can be one or zero items. This makes it possible to animate a single element entering or leaving. Similarly, you can animate a new element replacing the current element, with the new element animating in while the current animates out. For example, we can implement a simple image carousel like this:
|
|
|
|
```javascript{10-12}
|
|
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
|
|
|
|
var ImageCarousel = React.createClass({
|
|
propTypes: {
|
|
imageSrc: React.PropTypes.string.isRequired
|
|
},
|
|
render: function() {
|
|
return (
|
|
<div>
|
|
<ReactCSSTransitionGroup transitionName="carousel">
|
|
<img src={this.props.imageSrc} key={this.props.imageSrc} />
|
|
</ReactCSSTransitionGroup>
|
|
</div>
|
|
);
|
|
}
|
|
});
|
|
```
|
|
|
|
### Disabling Animations
|
|
|
|
You can disable animating `enter` or `leave` animations if you want. For example, sometimes you may want an `enter` animation and no `leave` animation, but `ReactCSSTransitionGroup` waits for an animation to complete before removing your DOM node. You can add `transitionEnter={false}` or `transitionLeave={false}` props to `ReactCSSTransitionGroup` to disable these animations.
|
|
|
|
> Note:
|
|
>
|
|
> When using `ReactCSSTransitionGroup`, there's no way for your components to be notified when a transition has ended or to perform any more complex logic around animation. If you want more fine-grained control, you can use the lower-level `ReactTransitionGroup` API which provides the hooks you need to do custom transitions.
|
|
|
|
## Low-level API: `ReactTransitionGroup`
|
|
|
|
`ReactTransitionGroup` is the basis for animations. It is accessible as `React.addons.TransitionGroup`. When children are declaratively added or removed from it (as in the example above) special lifecycle hooks are called on them.
|
|
|
|
### `componentWillEnter(callback)`
|
|
|
|
This is called at the same time as `componentDidMount()` for components added to an existing `TransitionGroup`. It will block other animations from occurring until `callback` is called. It will not be called on the initial render of a `TransitionGroup`.
|
|
|
|
### `componentDidEnter()`
|
|
|
|
This is called after the `callback` function that was passed to `componentWillEnter` is called.
|
|
|
|
### `componentWillLeave(callback)`
|
|
|
|
This is called when the child has been removed from the `ReactTransitionGroup`. Though the child has been removed, `ReactTransitionGroup` will keep it in the DOM until `callback` is called.
|
|
|
|
### `componentDidLeave()`
|
|
|
|
This is called when the `willLeave` `callback` is called (at the same time as `componentWillUnmount`).
|
|
|
|
### Rendering a Different Component
|
|
|
|
By default `ReactTransitionGroup` renders as a `span`. You can change this behavior by providing a `component` prop. For example, here's how you would render a `<ul>`:
|
|
|
|
```javascript{1}
|
|
<ReactTransitionGroup component="ul">
|
|
...
|
|
</ReactTransitionGroup>
|
|
```
|
|
|
|
Every DOM component that React can render is available for use. However, `component` does not need to be a DOM component. It can be any React component you want; even ones you've written yourself!
|
|
|
|
> Note:
|
|
>
|
|
> Prior to v0.12, when using DOM components, the `component` prop needed to be a reference to `React.DOM.*`. Since the component is simply passed to `React.createElement`, it must now be a string. Composite components must pass the factory.
|
|
|
|
Any additional, user-defined, properties will be become properties of the rendered component. For example, here's how you would you render a `<ul>` with css class:
|
|
|
|
```javascript{1}
|
|
<ReactTransitionGroup component="ul" className="animated-list">
|
|
...
|
|
</ReactTransitionGroup>
|
|
```
|