0

I'm trying to transition between 3 conditionally rendered components when I click on them. I'm trying to achieve this by using TransitionGroup from the react-transition-group. This is what I have so far:

<div className="transitionContainer">
        <Transition in={this.state.validFiles && this.state.dotted} timeout={duration}>
          {state => (
            <>
              {this.state.validFiles && this.state.dotted ? (
                <div className={`col fade fade-${state}`} onClick={this._handleDotted}>
                  <DottedPortrait state={this.state} />
                </div>
              ) : null}
            </>
          )}
        </Transition>
        <Transition in={this.state.validFiles && this.state.square} timeout={duration}>
          {state => (
            <>
              {this.state.validFiles && this.state.square ? (
                <div className={`col fade fade-${state}`} onClick={this._handleSquare}>
                  <SquaredPortrait state={this.state} />
                </div>
              ) : null}
            </>
          )}
        </Transition>
        <Transition in={this.state.validFiles && this.state.line} timeout={duration}>
          {state => (
            <>
              {this.state.validFiles && this.state.line ? (
                <div className={`col fade fade-${state}`} onClick={this._handleLine}>
                  <LinePortrait state={this.state} />
                </div>
              ) : null}
            </>
          )}
        </Transition>
      </div>

While this code works for the entering state of each conditional render, the exit animation is not because the component is unmounted before transition group can apply the exiting and exited classes. What's the best way to tackle this?

Below is the handle functions for these components:

handleValidFiles = () => {
console.log(this.state);
this.setState({
  validFiles: true,
  dotted: true,
  square: false,
  line: false
 });
};
_handleDotted = () => {
console.log(this.state);
this.setState({
  dotted: !this.state.dotted,
  square: !this.state.square
});
};

_handleSquare = () => {
console.log(this.state);
this.setState({
  square: !this.state.square,
  line: !this.state.line
});
};

_handleLine = () => {
console.log(this.state);
this.setState({
  line: !this.state.line,
  dotted: !this.state.dotted
});
};
  • 1
    not sure what you mean, check this [codesandbox](https://codesandbox.io/s/divine-fire-fj8q7) – iamhuynq Apr 02 '20 at 12:14
  • @iamhuynq thanks for this. I think the reason the sandbox is working is because you aren't conditionally mounting and unmounting the components, which is what I'm struggling with. I've gotten the enter animation to work onClick, but the exit animation isn't working because the component unmounts before the exit classes can be applied. I'm wondering how can I unmount after the transition completes with having to write more functions – Shivam Sinha Apr 02 '20 at 18:48

1 Answers1

0

Figured it out, albeit this is definitely not an elegant solution. The problem was that I was conditionally rendering components inside of the TransitionGroup when I should've been using the TransitionGroup to render the components.

<Transition
          in={this.state.validFiles && this.state.dotted}
          unmountOnExit
          onExited={this._handleToSquare}
          timeout={duration}
        >
          {state => (
            <div className={`col fade fade-${state}`} onClick={this._handleDotted}>
              <DottedPortrait state={this.state} />
            </div>
          )}
        </Transition>
        <Transition
          in={this.state.validFiles && this.state.square}
          unmountOnExit
          onExited={this._handleToLine}
          timeout={duration}
        >
          {state => (
            <div className={`col fade fade-${state}`} onClick={this._handleSquare}>
              <SquaredPortrait state={this.state} />
            </div>
          )}
        </Transition>
        <Transition
          in={this.state.validFiles && this.state.line}
          onExited={this._handleToDotted}
          unmountOnExit
          timeout={duration}
        >
          {state => (
            <div className={`col fade fade-${state}`} onClick={this._handleLine}>
              <LinePortrait state={this.state} />
            </div>
          )}
        </Transition>

With that handled, I also needed onExited callback function to trigger the render of the next component. Notice the _handleTo[xxxx] methods on the onExit prop.