DEV Community

Cover image for React beautiful animation reordering the list of items
Toan Tran
Toan Tran

Posted on • Updated on

React beautiful animation reordering the list of items

Requirement

Suppose you have a list of items ( it could be a product list, user ranking, or whatever). You asked to implement the upvote with React. How to make it appealing?
In the case of this article, I would demo a list of products, and there will be a button to upvote a product item.

Product list upvote

First few lines of code for a simple product list

Simple product list

Assume we are going to fetch a list of products from the server and keep it in state. When the user clicks on the upvote button, we will increase the vote by one.

Initiative

  • What is going to change when the list reorder? The position of product item

getBoundingClientRect](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect) WebAPI provide us DOMRect of an element (which are left, top, right, bottom, x, y, width, and height properties)

Great. We have a product item's top and left. These properties are likely to change when the element goes up or down in the list.

  • How to keep the previous position of items so we can add animation when there is a change? If we can have a reference of the product list, we can trigger some action whenever there is a change. Also, we can compare the difference between the previous position and the next position

createRef and useRef come in place to help.

  • We need to have a way to intervene in between state changes to add animation. What React hooks should we use here?

useLayoutEffect to read layout from the DOM and synchronously re-render. Updates scheduled inside useLayoutEffect will be flushed synchronously before the browser has a chance to paint.

Okay, now we know how we can access the state of layout in between

  • The tricky thing here is how to make the upvoting smooth. CSS Transitions came to my mind such a solution.

transform and transition go with translate

Implementation

  • Add ref to the product list with createRef

createRef

  • Create a custom hook to separate the logic

use custom hook

custom hook

  • An object to store DOMRect of every single item and a boolean ref to not running animation on the first run

To keep track of the DOMRect, we use product id. The origin key must be a not-changed unique key so that the product id would be the best in this case.

  • useLayoutEffect - the most important part

useLayoutEffect

The logic here is to check every item on the list.

const previous = origins.current[key]; is the previous position of the item

const next = child.getBoundingClientRect(); is the next position of the item after list reorder

This line of code is for checking the differences. If there is a difference, we applied animation to this item.

Play animation

Using transform and transition in animation

Image description

Issue

I found an issue when scrolling a list. It causes the product element position to change. I added the code to update the item position when a scroll event trigger.

useScroll

Source code

You can find all source code here: ( with React 18, Typescript ) https://github.com/toantd90/react-flip.

  • faker generate sample data
  • plop for create a consistent templates for pages, components, etc

Any comments would be appreciated!!!

Top comments (1)

Collapse
 
joshuaaron_ profile image
Josh Reynolds

Decent solution. Since updates to refs don't cause rerenders, placing it as a dependency for useLayoutEffect is pointless as this will never trigger the effect to be called again.