What is the best way to smoothly move a fixed-size div from one container to another during a re-render process?

Introduction

Anticipated change

Similar, though not identical to my scenario:

  1. Situation 0: Imagine you have a container (chessboard with divs for game pieces) and a dead-pieces-view (container for defeated pieces). The positioning of these containers is determined by CSS rules and device/media parameters, managed by the browser.
  2. Situation 1: A piece is captured and needs to be smoothly transitioned from the board to the dead-pieces view in the correct location.

I can accurately identify the moving divs using unique ids/keys.

Additional Requirements: I am using React, so I anticipate that the smooth transition can be achieved simply by updating the rendering from State0 to State1. (Or, at the very least, with minimal imperative code additions)

Here is a link to my sandbox project: https://codesandbox.io/s/crazy-pasteur-lr4ku

Prior Attempts:

  1. I experimented with using react keys and ids to track the moving div. However, the issue was not specific to React; even manual movement of the div using pure JS (appendChild) did not result in a smooth transition.
  2. I also attempted to use react-pose as it seemed like a potential solution. Unfortunately, it appeared to be limited to animating ul/li elements exclusively, while other animated elements on the page remained independent from one another (or perhaps I did not fully explore the framework's capabilities).

Answer №1

I stumbled upon a concept that seems like it could be a good fit for my needs.

Abstract:

When div1 changes position to div1', I immediately kill div1 while smoothly animating the transition of div1' from its last known place using keyframes, with 1 iteration.

Technical:

In React: componentWillUnmount saves the current position of the uniquely identified element.

In React: componentDidMount calculates the difference, creates an animation on the fly, and uses setState to re-render with the animation.

Unfortunately, this approach requires some global states and other anti-patterns, but it does the trick.

Working example(based on question): https://codesandbox.io/s/muddy-hill-ti6bs

Key points:

  1. No absolute positioning is used anywhere
  2. The containers resize according to CSS properties when the page/browser/viewport is resized
  3. The target div smoothly moves to its new spot upon re-render, even if the previous animation was interrupted.

Answer №2

It is important to:

  • Maintain consistency in the parent element during re-renders in order to prevent React from creating/deleting a new child. To achieve this, the parent container must have a persistent key value such as
    key: idx === parentContainer ? "withBlock" : idx
    .
  • Ensure there is a transitionable property available, like setting position: absolute in the styles and allowing modification of the top value.

Once these conditions are met, you can update the transitionable property after each render by utilizing the following code snippet:

const Block = () => {
  const ref = useRef();
  useEffect(() => {
    if (!ref.current) {
      return;
    }
    const el = ref.current;
    const {top} = el.parentNode.getBoundingClientRect();
    el.style.top = `${top + border}px`;
  });
  return <div className="block" ref={ref} />;
};

https://codesandbox.io/s/busy-mendeleev-7s2zg

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it possible to transfer data between pages by utilizing state in the Next.js 13 App directory?

Can Nextjs 13 App Router be used to efficiently pass previewData from MainComponent.jsx to Preview.jsx as a State, without involving query parameters or props? I want to transfer the data as state from MainComponent.jsx, then navigate to the Result.jsx com ...

The backend post request is returning only "undefined" in JavaScript

Hey there, I'm still learning JS so please bear with me. I've been working on incrementing a value in a JSON file within my JS backend app. However, whenever I try to increase the associated value by the key, it ends up creating a new section la ...

After a period of 10 minutes with no activity, proceed to the next page

I am in the process of developing a custom local website that will be displayed on a large touch screen at my current workplace. Only one user can interact with it at a time. My client has requested a screensaver feature to appear after 10 minutes of no i ...

Adding a toggle button within a Syncfusion DataGrid table is a simple and effective way to enhance

Is it possible to add a toggle button inside a column (table) using Material UI in syncFusion? I couldn't find the information I need on the syncFusion website. Here is a sample code for adding a syncfusion table. Where should I mention the type for ...

Ensure that divs can adjust in size while maintaining the same dimensions of their contained

I'm currently facing a slight issue with these two divs. I want them to be scalable, which I know can be achieved by using percentages, but every time I do so, the divs end up out of position. When I try setting widths, they look fine in Google Chrome ...

Eliminate the lower boundary of a divisional table

I'm having an issue with displaying images in a div table. Each image has a border at the bottom, which is around 2-5 pixels wide. Unfortunately, as a new user, I am unable to send any images. My main goal is to remove this unwanted border from the ...

Generating dynamic @returns annotations in JSDoc based on the value of @param

How can I properly document the function in order for vscode-intellisense to recognize that getObject("player") returns a Player type and getObject("bullet") returns a Bullet type? /** * @param {string} type * @return {????} */ function getObject(type ...

Displaying content based on changing conditions fetched from the database

We are currently developing a dynamic form system where users can create custom questions in the admin panel and set conditions to display them based on the values of other questions. ng-show="((UserCode==10003 && Name=='Ankur') ||(State ...

I am encountering an issue where the POST data is not being successfully sent using XMLHttpRequest unless I include

I have a unique website where users can input a cost code, which is then submitted and POSTed to a page called 'process-cost-code.php'. This page performs basic validation checks and saves the information to a database if everything is correct. T ...

The Bootstrap Navbar appears hidden beneath other elements on mobile devices

While using bootstrap to style my header contents, I encountered a strange issue. The navbar that appears after clicking on the hamburger menu is displaying behind all the components. Even though I've set the z-index to the maximum value, it still doe ...

Navigate the Angular interceptor route to display a 404 error page when clicking on a `<a href="#">` tag

When using href="#" as a placeholder in html, I encountered an issue where Angular was unable to recognize it and would route to the 404 page despite having the following configuration in the module. How can this problem be resolved? .config( function m ...

Is it possible to switch variations in WP-Commerce from drop-down menus to text input

Currently exploring ways to customize the size variations on an e-commerce website similar to Using WP Commerce, the size variations are originally displayed in select fields by default. <select class="wpsc_select_variation ...

What is the best way to delete a specific date from local storage using Angular after saving it with a key

I'm attempting to clear the fields in my object (collectionFilter) from local storage using localStorage.removeItem('collectionFilter'). All fields are removed, except for the date fields. Please note that I am new to JavaScript and Angular. ...

Error: The function prevDeps.join is not defined in Next.js

I need assistance in creating a search bar using next js and firebase. The functionality involves extracting the slug from the URL and processing it through my search algorithm. However, I encountered an issue where if the user utilizes the search bar mult ...

Tips for submitting a form using alternative methods of action

Currently, I am facing a challenge in retrieving information from a database using submit buttons with the same name. I assign a value to these buttons, which corresponds to the id of the row, enabling me to perform different actions. However, I am unsure ...

Is there a way to substitute all underscores in HTML tag IDs and classes with a hyphen symbol?

I recently realized that I used underscores instead of hyphens in some of my CSS class and id names. To correct this, I want to replace all underscores with hyphens using the sublime text replace feature (ctrl + H). Is there a way to change underscores to ...

The Bootstrap validator triggers the form submission only after the second click

When I click on the submit button, I am attempting to submit a form that has its default action prevented and first checks a condition before proceeding. Below is the code snippet: $('#payment-form').bootstrapValidator({ live: 'dis ...

Challenges with navbars and Bootstrap

Just started using twitter-bootstrap and I'm trying to customize the navbar by removing borders and padding, adding a hover effect for links with a different background color, and setting margins of about 10px on the left and right. However, I'm ...

Utilizing JQuery to select list items for pagination purposes

I am currently working on a pagination script and everything seems to be functioning well, except for one minor issue. I am struggling with triggering an action when the page number (li) is clicked. The pagination data is being retrieved via ajax and disp ...

The no-unused-expressions rule is triggered when an assignment or function call is expected

I'm just starting out in full stack development and I'm experimenting with coding to improve my understanding of frontend using React JS and Material UI. While working on this component, I encountered an error in the console at line 75 (this.prop ...