React: Using React-Spring To Animate Crossfading Images
By: Joe Keohan
Tags: Front End Development, React, Data Visualization, D3js, React Spring

Image by author

During the refactor of Streetball Mecca from a version using only D3 to a version that leverages D3 for it’s helper functions and React for everything else, I replaced d3.transition with React-Spring in order to animate the fadein/fadeout of the circles on the map. You can read more about how I implemented that solution in this previous article: React & D3: Rendering Circles On A Map Using React-Spring Transitions.

While I was refactoring the park image into its own component, I once again found the need to replace d3.transition with an alternative solution and decided to give React-Spring another try.

The React-Spring Docs And More Research

The d3.transition used to fadein the park images felt somewhat choppy. The reason being is that it just replaced the previous background image first and then used opacity to create the fadein. Here is the original code.

Image by author

I was never quite happy with that UX implementation and always wanted to apply a smooth crossfade between the incoming/outgoing images. I also knew that this would require a refactor of the original D3 code but I had already reached the point in that project where things worked well enough and needed to move onto the next D3 project.

However, I was now presented with the opportunity to implement the crossfade, along with another reason to work with React-Spring.

Working Example

The first thing I did was review the docs to hopefully find a working example of crossfading images. React-Spring provides several methods to work with and after looking over the docs the useTransition hook caught my eye so I started there.

I browsed down to the demo samples provided and in less than 30 secondsI found a working example that looped over transitioning 4 images in a continuous loop.

Image from React-Spring demo

After reviewing the code it was obvious that useTransition was being used to control the transitions but I felt I needed to do some additional research to get a better understanding on how it differed from useSpring.

Additional Research

So I did a Google search for ‘useTransition vs useSpring’ and came across the article “Creating Complex Animation in React using react-spring” written by Joshua Hall. In it he discusses use cases for useSpring, useSprings, useTrail, and useTransition and I felt the article really provided the additional context I was looking for.

As for the comparison between useSpring and useTransition he states that:

One problem with useSpring is that it doesn’t give us any control over the lifecycle of our component

And further followed by:

Instead we can use useTransition to control the animations as it is mounted and unmounted from the view.

Although this was my first attempt at working with useTransition I did recall implementing animations using several class lifecycle methods once before. So after searching through the hundreds of codepens I’ve written over the years I came across animating the alphabet (Jan 2018) which implemented the animations using the React-Transition-Group library.

It was written using class Components and made use of the lifecycle methods componentWillEnter and componentWillLeave, of which I had never seen before that time, and componentWillReceiveProps.

Image by author

In the working example, useTransition had also been configured to make use of the keywords ‘enter’ and ‘leave’ so it was clear now how it would trigger the animations to coincide with the above lifecycle methods.

Image by author

Also in the example, I could see that setInterval was updating the index state value every 5 seconds and that during the re-render a new useTransition would be instantiated and assigned that new value.

useTransition returned an array which was then mapped over and returned a new animated.div with each iteration.

Image by author

More Understanding Required

I wasn’t quite sure what was included in the transitions array and I was still curious to understand the entire process so I added console log to take a look.

I let it run a few times and noticed a pattern. When the next image was about to be displayed the array would contain 3 elements, 2 for leave and 1 for enter. Once the image was faded in, the array would remove the leave at the first position and update enter to update for the last.

Image by author

So it seemed that useTransition would remove that element from the array once the transition was completed and the element removed from the DOM. I also noticed that the key value would keep incrementing and associated with the standard way React keeps track of elements rendered via a map.

Here is the full code sample from the working example so you can see how it all ties together.

Image by author

I now felt like I had a grasp of what was going on and decided it was time to apply this understanding to transitioning the park images.

Implementing The Transitions

The first step was to import the useTransition and animated methods from React Spring.

Image by author

In the working example, useTransition was reassigned a new image based on updated index value. In my configuration, however, the images are being passed down as props.

Since the component is being re-rendered each time new props are passed it made sense to assign the current prop value to useTransition, which in this case was the activePark object.

Image by author

I also added a console log to see if the transitions would follow the same pattern as before. The pattern was similar although the arrays included one less element.

Image by author

Not quite sure why the change, but I’m certain if this weighs on my developer conscience long enough, I will revisit it at a later time and try to figure it out.

Rendering The Images

As for rendering the images I was able to reuse all of the code in the working example, with only a few edits. One of those edits was the need to include some conditional logic to run when the activePark object existed.

Image by author

I also added a console log to see what was inside of the map. The elements aligned with what I expected. The item was the activePark object, the props were the transitions, and the key corresponded to the elements which was how useTransition kept track of them as they were rendered.

Image by author

The key value would then increase every time a new image was rendered.

Image by author

Conclusion

This refactor from d3.transition to React-Spring useTransition was fairly easy. Along the way I made some discoveries and feel I now have a much better understanding of what’s happening under the hood. It’s moments like these that I realize how my students must feel when they want to know the why but we only had time to teach the how.

I did work through another solution originally that was a bit more complex and made use of useState and useEffect along with alternating the placement of images in an array.

It wasn’t until I started writing this article and documenting my thoughts that I decided to refactor that solution. I had the gut feeling it was too complicated and a simpler approach could be found.

Anyway here is the CodeSandbox if you wanted to take a further look.

Additional Articles

Here are some additional articles I’ve written as per refactoring the code from D3 => React. If you have any thoughts, suggestions or comments I’d love to hear them.