Consider a use case: a block with a text inside (text is fetched from store). When text changes - block smoothly goes away and the other block appears.
Pseudo code for better illustration:
import TransitionGroup from 'react-addons-transition-group'
@connect((state) => ({text: state.text}))
class Container extends React.Component {
render() {
return (
<div>
<TransitionGroup>
<Block key={this.props.text}/> // change block when text changes
</TransitionGroup>
</div>
)
}
}
@TransitionWrapper() // pass componentWillEnter through wrapper
@connect((state) => ({text: state.text}), null, null, {withRef: true})
class Block extends React.Component {
componentWillEnter(callback) {
// fancy animations!!!
const el = ReactDOM.findDOMNode(this);
TweenMax.fromTo(el, 1, {
alpha: 0,
}, {
alpha: 1,
onComplete: callback
});
}
componentWillLeave (callback) {
const el = ReactDOM.findDOMNode(this);
TweenMax.to(el, 1, {
alpha: 0,
onComplete: callback
});
}
render() {
return (
<div>{this.props.text}</div>
)
}
}
What happens when state.text changes?
- New
Block
appears, becausekey
is changed;componentWillEnter
starts the animation for it. Great. - Old block gets re-rendered and
componentWillLeave
starts the animation for it. - When first animation finishes re-render happens again.
The issue is the step no 2: old element should disappear with the old data, but due to re-render it changes his content to a new one from store
, so user see this:
store.text = 'Foo'
. User see one Block with text 'Foo' on the screen.store.text = 'Bar'
. User see two Blocks, both with text 'Bar' on the screen. One block is disappearing.- Animation finishes, user see one Block with text
Foo
on screen.
I believe using transitions is pretty common nowadays and this should be a common issue, but I was surprised I couldn't find anything related.
Best idea I can think is to "freeze" props on the element when it's about to leave (or passing previous store
, so it re-renders with previous data), but it feels hacky to me.
What's the best way to solve this problem?