Skip to content

Commit

Permalink
[fixed] New props are flushed before any new transition
Browse files Browse the repository at this point in the history
fixes #40.
  • Loading branch information
jquense committed Jan 28, 2016
1 parent 05748c6 commit 13d9331
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 20 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"sinon": "^1.15.4",
"sinon-chai": "^2.8.0",
"style-loader": "^0.12.3",
"teaspoon": "^6.1.1",
"webpack": "^1.12.2",
"webpack-dev-server": "^1.12.0",
"yargs": "^3.14.0"
Expand Down
50 changes: 30 additions & 20 deletions src/Transition.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,31 +44,21 @@ class Transition extends React.Component {
}

componentWillReceiveProps(nextProps) {
const status = this.state.status;
if (nextProps.in) {
if (status === EXITING) {
this.performEnter(nextProps);
} else if (this.props.unmountOnExit) {
if (status === UNMOUNTED) {
// Start enter transition in componentDidUpdate.
this.setState({status: EXITED});
}
} else if (status === EXITED) {
this.performEnter(nextProps);
}

// Otherwise we're already entering or entered.
} else {
if (status === ENTERING || status === ENTERED) {
this.performExit(nextProps);
if (nextProps.in && this.props.unmountOnExit) {
if (this.state.status === UNMOUNTED) {
// Start enter transition in componentDidUpdate.
this.setState({status: EXITED});
}

// Otherwise we're already exited or exiting.
}
else {
this._needsUpdate = true
}
}

componentDidUpdate() {
if (this.props.unmountOnExit && this.state.status === EXITED) {
const status = this.state.status;

if (this.props.unmountOnExit && status === EXITED) {
// EXITED is always a transitional state to either ENTERING or UNMOUNTED
// when using unmountOnExit.
if (this.props.in) {
Expand All @@ -77,6 +67,26 @@ class Transition extends React.Component {
this.setState({status: UNMOUNTED});
}
}

// guard ensures we are only responding to prop changes
if (this._needsUpdate) {
this._needsUpdate = false;

if (this.props.in) {
if (status === EXITING) {
this.performEnter(this.props);
}
else if (status === EXITED) {
this.performEnter(this.props);
}
// Otherwise we're already entering or entered.
} else {
if (status === ENTERING || status === ENTERED) {
this.performExit(this.props);
}
// Otherwise we're already exited or exiting.
}
}
}

componentWillUnmount() {
Expand Down
26 changes: 26 additions & 0 deletions test/TransitionSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import ReactTestUtils from 'react-addons-test-utils';
import { render } from './helpers';
import tsp from 'teaspoon';
import Transition, {UNMOUNTED, EXITED, ENTERING, ENTERED, EXITING} from
'../src/Transition';

Expand Down Expand Up @@ -30,6 +31,31 @@ describe('Transition', function () {
expect(instance.state.status).to.equal(EXITED);
});

it('should flush new props to the DOM before initiating a transition', function(done) {
tsp(
<Transition
in={false}
timeout={0}
enteringClassName='test-entering'
onEnter={node => {
expect(node.classList.contains('test-class')).to.equal(true)
expect(node.classList.contains('test-entering')).to.equal(false)
done()
}}
>
<div></div>
</Transition>
)
.render()
.tap(inst => {
expect(inst.dom().classList.contains('test-class')).to.equal(false)
})
.props({
in: true,
className: 'test-class'
})
});

describe('entering', ()=> {
let instance;

Expand Down

0 comments on commit 13d9331

Please sign in to comment.