DEV Community

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

Posted on • Edited on

9 5

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!!!

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post →

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.

nextjs tutorial video

Youtube Tutorial Series 📺

So you built a Next.js app, but you need a clear view of the entire operation flow to be able to identify performance bottlenecks before you launch. But how do you get started? Get the essentials on tracing for Next.js from @nikolovlazar in this video series 👀

Watch the Youtube series

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay