2

Using React Transition Group v2, I want to be able to smoothly transition between an element of text and a loading spinner.

Without any CSSTransitionGroup element, I have the following code:

{isFetchingEvents ? (
  <LoadingSpinner />
) : (
  <div>Show More</div>
)}

My initial, and naive, way of approaching this at first would be to use the following:

<CSSTransition
  in={isFetchingEvents}
  timeout={3000}
  classNames="marketGroupFade"
>
  <LoadingSpinner />
</CSSTransition>
<CSSTransition
  in={!isFetchingEvents}
  timeout={3000}
  classNames="marketGroupFade"
>
  <div>Show More</div>
</CSSTransition>

But this isn't a good solution, because the ternary operator has gone, and repetition of the in prop is present, as well as repetition of the classNames. It does transition between the two, but the transition is rough as each component comes in and out.

Is there a neat solution to transitioning between two components that would be rendered in a ternary operator?

Rob
  • 14,746
  • 28
  • 47
  • 65
alanbuchanan
  • 3,993
  • 7
  • 41
  • 64
  • Why exactly do you not want to use the TransitionGroup. If you're looking to synchronized you all the bib and bobs of your gonna have really hard time with out using it. – Geoff Taylor Sep 26 '18 at 19:14
  • Could you elaborate on why I would need `TransitionGroup`? The main RTG contributor explained that it is only necessary for exceptional use-cases https://github.com/reactjs/react-transition-group/issues/372#issuecomment-403652224 – alanbuchanan Sep 27 '18 at 09:59

1 Answers1

2

I figured I make this an answer. Use the TransitionGroup component. TransitionGroup is the third component the react-transition-group package provided. That issue in the link from your comment is referring to the first and lowest level component Transition. The TransitionGroup component works in combination with CSSTransition or Transition. Its handles the in prop on any child CSSTransition or Transition. When one of the two are place inside it set the in prop on the child to true and vice versa when the child is removed and when you need a like more flexible you can use the function as children pattern to pass the state to the transition and manually set the in prop. Look at the below as example and CodePen for more details you can also view the documentation here

// Create CSSTransition Higher Order Component
const slideHOC = (InputComponent) => {
   return props => (
     <CSSTransition {...props}>
       <InputComponent className="slide" />
     </CSSTransition>
   );
};

// Create CSSTransition components it can be a list but it doesn't have to be.
const groupItems = [ 
  {
    id: uuid.v4(),
    element: slideHOC(props => (<h3 {...props}>Hello</h3>))
  }, { 
    id: uuid.v4(),
    element: slideHOC(props => (<h3 {...props}>World!</h3>))
  },
];

// Reusable CSSTransition props
const transProps = {
  appear: true,
  timeout: {
    enter: 350,
    exit: 500,
  },
  classNames: "slide",
};

// And add this somewhere in your render component 
<TransitionGroup
   className="test-component-one"
   childFactory={child => React.cloneElement(child, transProps)}
>
  {groupItems.map(({ id, element: Element }) => {
    return (<Element {...transProps} key={id} />)
  })}
</TransitionGroup>

// If you want to map an array to can do it like so. Note the key prop on the
// instances of FadeHOC must be set and unique to the CSSTransition for the
// childFactory to work.
FadeHoc = faceHOC(props => (<h3 {...props}>Hello</h3>));
<TransitionGroup
   className="test-component-one"
   childFactory={child => React.cloneElement(child, transProps)}
>
  <FadeHOC {...transProps} key={id} />
  <FadeHOC {...transProps} key={id} />
</TransitionGroup>

// Or if you want more flexibility you can do something like this
<TransitionGroup
   className="test-component-one"
   childFactory={child => React.cloneElement(child, transProps)}
>
  {(state) => (
    <FadeHOC in={state === 'entered'} {...transProps} key={id} />
    <FadeHOC in={state === 'exited'} {...transProps} key={id} />
  )}
</TransitionGroup>

CodePen to see it in action.

TransitionGroup also has the ability to continue rendering items that aren't still mounted that where the childFactory prop comes in. Although I'm not completely sure how every part of it works. It all its child elements and wraps them in a container component to be render it even after the child has been unmounted. This way exit animation can be animated.

Geoff Taylor
  • 496
  • 3
  • 17
  • Thanks for the example, sorry I got confused with the name of the component. Using `TransitionGroup` makes sense. – alanbuchanan Sep 28 '18 at 10:18
  • No problem. `react-transition-group` is a great package, it just uses some of React's more advanced concepts and patterns so it can be hard to wrap you head around at times, so I understand the confusion. – Geoff Taylor Sep 28 '18 at 21:07