Skip to content

Instantly share code, notes, and snippets.

@renarsvilnis
Last active April 4, 2017 20:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save renarsvilnis/bb083fa50c64221c49f43169076cdf31 to your computer and use it in GitHub Desktop.
Save renarsvilnis/bb083fa50c64221c49f43169076cdf31 to your computer and use it in GitHub Desktop.
<DelayMount/> component

React Component that allows to delay mounting/unmounting* (see examples) of a React component.

Reason behind it: facebook/react#8280

Examples

In order for the component to work with ReactCSSTransitionGroup, it must be called within DelayMount

Delaying enter

<DelayMount transitionEnterDelay={1000}>
  <ReactCSSTransitionGroup transitionName="custom-transition" transitionEnterTimeout={2000}>
    <h1>{'Hello World'}</h1>
  </ReactCSSTransitionGroup>
</DelayMount>

Delaying leave

Delaying leave is with component lifecycle hooks is not possible as a plain React component lifecycle componentWillUnmount function doesn't support async behaviour (callbacks, promises). A workaround is to manage the mounted state outside of DelayMount and pass it in as render.

DelayMount will wait for ReactCSSTransitionGroup to leave then it will remove the component from the DOM.

Doesn't work if unmounting DelayMount itself

const show = false;
const leaveTimeout = 1000;

<DelayMount 
  render={show}
  // Delay unmounting by specifing the duration of the
  transitionLeaveTimeout={leaveTimeout}
>
  <ReactCSSTransitionGroup
    transitionName="custom-transition"
    transitionLeaveTimeout={leaveTimeout}
  >
    {show && (<h1>{'Hello World'}</h1>)}
  </ReactCSSTransitionGroup>
</DelayMount>
import {PureComponent, PropTypes} from 'react';
export default class DelayMount extends PureComponent {
static propTypes = {
render: PropTypes.bool.isRequired,
children: PropTypes.any,
transitionEnterDelay: PropTypes.number.isRequired,
transitionLeaveTimeout: PropTypes.number.isRequired
}
static defaultProps = {
render: true,
transitionEnterDelay: 0,
transitionLeaveTimeout: 0
}
constructor (props) {
super(props);
this.state = {
shouldMount: false
};
}
componentDidMount () {
if (this.props.render) {
this.setEnterTimeout(this.props);
}
}
componentWillUpdate (nextProps, nextState) {
if (nextProps.render) {
this.setEnterTimeout(nextProps);
} else {
this.setLeaveTimeout(nextProps);
}
}
componentWillUnmount () {
this.clearEnterTimeout();
this.clearLeaveTimeout();
}
setEnterTimeout (props) {
if (this.enterTimeout) {
return;
}
this.clearLeaveTimeout();
this.enterTimeout = window.setTimeout(() => {
this.setState({shouldMount: true});
this.clearEnterTimeout();
}, props.transitionEnterDelay);
}
setLeaveTimeout (props) {
if (this.leaveTimeout) {
return;
}
this.clearEnterTimeout();
this.leaveTimeout = window.setTimeout(() => {
this.setState({shouldMount: false});
this.clearLeaveTimeout();
}, props.transitionLeaveTimeout);
}
clearEnterTimeout () {
if (this.enterTimeout) {
window.clearTimeout(this.enterTimeout);
this.enterTimeout = null;
}
}
clearLeaveTimeout () {
if (this.leaveTimeout) {
window.clearTimeout(this.leaveTimeout);
this.leaveTimeout = null;
}
}
render () {
return this.state.shouldMount ? this.props.children : null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment