React-transition-group: Transitions not applying when component mounts with React@16

Created on 3 Oct 2017  ·  18Comments  ·  Source: reactjs/react-transition-group

Do you want to request a feature or report a bug?
Bug

What is the current behavior?
When trying to apply the transition on componentDidMount, the transition effect does not work.

Steps to reproduce:
1) create-react-app [project-name]
2) cd [project-name]
3) yarn add react-transition-group
4) Copy content from here and paste on the src/App.js
5) Copy this code and past into src/App.css

.fade {
  opacity: 0;
  transition: opacity 4s linear;
}
.fade.in {
  opacity: 1;
}

What is the expected behavior?
The transition effect should be applied when the componentDidMount is fired. However, it doesn't happen.
If you comment the line 46 and uncomment the setTimeout(() on line 48, 49, 50, 51. It will fix the bug.

Which versions, and which browser / OS are affected by this issue? Did this work in previous versions?
This bug only reproduces with the latest version of React (16).

something tells me that it is related to the new react fiber architecture

Most helpful comment

Use keyframes instead. Works good for me.

```.container {

&.fadeIn {
animation-name: fadeIn;
animation-duration: 1s;
}
}

@keyframes fadeIn {
from {
opacity: 0;
}

to {
opacity: 1;
}
}```

All 18 comments

I think I have the same problem… This is just the samples for Transition & TransitionGroupfrom the docu page merged together.

What is the expected behavior?
Items are faded in as they are added.
The function inside Transitionin is called with state exited, entering and entered, if I place a debugger there the animation works fine. Without the debugger there is no fade effect.
It seems that React 16 optimised the rendering so well that there is no redraw cycle between exited and entering, which destroys our animation effect.

Which versions, and which browser / OS are affected by this issue?
react: ^16.0.0
react-dom: ^16.0.0
react-transition-group: ^2.2.1

import React from 'react';
import TransitionGroup from 'react-transition-group/TransitionGroup';
import Transition from 'react-transition-group/Transition';

const duration = 300;

const defaultStyle = {
  transition: `opacity ${duration}ms ease-in-out`,
  opacity: 0,
}

const transitionStyles = {
  entering: { opacity: 1 },
  entered:  { opacity: 1 },
};

const Fade = ({ in: inProp, children, ...otherProps }) => (
  <Transition in={inProp} timeout={duration} { ...otherProps }>
    {(state) => (
      <div style={{
        ...defaultStyle,
        ...transitionStyles[state]
      }}>
        { children }
      </div>
    )}
  </Transition>
);

class AnimationGroup extends React.Component {
  constructor(props) {
    super(props)
    this.state = {items: ['hello', 'world', 'click', 'me']}
  }
  handleAdd() {
    const newItems = this.state.items.concat([
      prompt('Enter some text')
    ]);
    this.setState({ items: newItems });
  }
  handleRemove(i) {
    let newItems = this.state.items.slice();
    newItems.splice(i, 1);
    this.setState({items: newItems});
  }
  render() {
    return (
      <div>
        <button onClick={() => this.handleAdd()}>Add Item</button>
        <TransitionGroup>
          {this.state.items.map((item, i) => (
            <Fade key={item}>
              <div>
                {item}{' '}
                <button onClick={() => this.handleRemove(i)}>
                  remove
                </button>
              </div>
            </Fade>
          ))}
        </TransitionGroup>
      </div>
    );
  }
}

export default AnimationGroup;

I made a proposal for a workaround this issue: https://github.com/reactjs/react-transition-group/pull/227

Check out previous issues on this. Transition is a low level component with no specific affordances for css transitions, those need to be handled in the wrapping component (or use CssTransition).

In this particular case you don't need a timeout you can reflow the browser, there are a few examples of this in previous issues and the components link in the note about it in the docs

@jquense users should _not_ expect Transition to work the same with react 16 as it does with react 15? I didn't see that in the note about it in the docs.
If that is not the case then one of the two is broken since they currently work differently.
Also, what previous issues are you referring to? I looked at all of the react 16 related issues in this repo and didn't see anything similar to this.

@TheSharpieOne I think @jquense is probably refering to #159. There are others but this one specifically discusses the manual reflow.

where does this issue end?

I wish there was an option to fix this reflow issue out of the box. The CSSTransition doesn't really support using variables which I needed in my general purpose Fade animation component.

I solved this by not using appear in my <Transition/> component and instead used a setTimeout of 1 ms in my componentDidMount and then after 1 ms I would render the <Transition/> component using in={true}. This fixed the issue mentioned here.

CSSTransition is built upon Transition, you should be able to do anything that you can do with Transition, with the addition of classes and reflow hack.

<CSSTransition in={in} timeout={200}>
  {state => (
    // ...
  )}
</CSSTransition>

@silvenon What is reflow hack? :/

CSSTransition forces a reflow in order for entering/appearing styles to work.

+1 👍 CSSTransition is breaking my CSS transition attributes

@krabbypattified could you open a new issue providing a demo?

Here is a demo. Hover over anything and hover/click on the pink circle. There is no transition in circle size. When I set the in attribute to always true, the circles now transition in size when I hover/click on them and everything works as expected.

https://codesandbox.io/s/ojzkr98m4y

I will open a new issue.

@krabbypattified feel free to include the same demo, you don't have to use our template.

Use keyframes instead. Works good for me.

```.container {

&.fadeIn {
animation-name: fadeIn;
animation-duration: 1s;
}
}

@keyframes fadeIn {
from {
opacity: 0;
}

to {
opacity: 1;
}
}```

Hell yeah! @tr3v3r _thank you_!

Holy shit this issue has like 4 "solutions" _none of which work_. Its a simple opacity change —_been doing it for years_— but wow do React components wreak havoc. Only thing I did different was add the fill-mode so that the faded-in effect would stick around:

.fadeIn {
  animation-name: fadeIn;
  animation-duration: 2s;
  animation-fill-mode: forwards;
}

Its just like what Scotty said:

The more they overthink the plumbing, the easier it is to stop up the drain.

I recommend using CSS Transitions instead, that's the feature that react-transition-group was built for. Like we previously said, most of the times what you really need is the CSSTransition component, not Transition. The author of the issue was trying to reinvent the appear prop and reflow hack at the same time, even though those features already exist (the docs were probably worse then, so I understand the confusion). I guess React 16 is making some kind of an optimization that breaks those hacks, but that doesn't diminish the fact that it's not the way this library should be used. I don't know what's the reason behind trying to reinvent these features, it's not clear from the examples, but I'd be happy to clear it up if anyone still has questions. I feel uneasy with the keyframes being considered as a fix because I don't think there was a problem to begin with. 🙂

Was this page helpful?
0 / 5 - 0 ratings