What is the best way to incorporate a smooth transition for an object as it appears on the screen in React?

After configuring my code to display a component in the HTML only if a specific hook is set to true, I encountered an issue with a CSS transition. The problem arises because the 'open' class is triggered at the same time the element becomes true, causing the transition to not work as expected. I've explored timed delays as a solution but they also don't seem to solve the issue.

// Hook for setting state
      const [mealOne_box, mealOne_boxSet] = useState(false);
      const [box_transition, setbox_transition] = useState(false);
      const [scroll, scrollSet] = useState(false);

// Prevent body scrolling behind popup
     if (scroll) {
            document.body.style.overflow = 'hidden';
        } else {
            document.body.style.overflow = 'unset';
        }

// Handle clicks for popup
      const mealOneClickHandler = (event) => {
            mealOne_boxSet(!mealOne_box);
            scrollSet(!scroll)
            setbox_transition(!box_transition)
        }


// Popup element

  {mealOne_box && (
                <div className='meal_popup'>
                    <div className={box_transition ? 'meal_popupElement open' : 'meal_popupElement'}>
                        <CancelIcon onClick={mealOneClickHandler} />
                        <img alt='' src={PancakeImage} />
                        <div className='text_scroll'>
                            <h2>Method:</h2>
                            <p>blablabla</p>
                        </div>
                    </div>
                    <div onClick={mealOneClickHandler} className='meal_popupBackground' />
                </div>
            )}




// CSS Styles

.meal_popupElement {
  position: fixed;
  margin: auto;
  margin-top: 6%;
  width: 95%;
  left: 50%;
  transform: translateX(-50%);
  background: white;
  border-radius: 15px;
  height: 80%;
  box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14),
    0px 1px 3px 0px rgba(0, 0, 0, 0.12);
  z-index: 2;
  overflow: hidden;

  p,
  h2 {
    padding-left: 1rem;
    padding-right: 1rem;
    font-family: "Open Sans", sans-serif;
  }
  p {
    margin-top: 0;
  }
  h2 {
    margin-bottom: 0.5rem;
    font-size: larger;
  }
  svg {
    position: absolute;
    display: flex;
    margin: 6px;
    width: auto;
    height: 35px;
    color: white;
    right: 0;
  }
  img {
    width: 100%;
    height: 30%;
    object-fit: cover;
    object-position: 0% 0%;
  }
  transition: opacity .25s ease-in-out;
  opacity: 0;
}

.meal_popupElement.open {
  opacity: 1;
}**

Answer №1

To make your component render .meal_popup first and then add the .open class afterwards for the transition to work properly, you can wrap

setbox_transition(!box_transition)
in either a Window.requestAnimationFrame() or
WindowOrWorkerGlobalScope.setTimeout()
call. This ensures that mealOne_box and box_transition are updated separately and trigger two distinct requests.

Since setState is asynchronous, there may still be issues with this approach, as React could batch updates and perform DOM updates simultaneously.

A working solution with a high delay looks like this:

const mealOneClickHandler = (event) => {
  mealOne_boxSet(!mealOne_box);
  scrollSet(!scroll);
  setTimeout(() => {
    setbox_transition(!box_transition);
  }, 1000);      
};

Using requestAnimationFrame might also require multiple calls and could pose more problems than using setTimeout:

const mealOneClickHandler = (event) => {
  mealOne_boxSet(!mealOne_box);
  scrollSet(!scroll);

  requestAnimationFrame(() => {
    requestAnimationFrame(() => {
      setbox_transition(!box_transition);
    });
  });      
};

Therefore, the optimal solution would be to utilize ReactCSSTransitionGroup. You can refer to this example, which provides a clearer explanation compared to the official documentation.

Answer №2

The fading in issue has been resolved, but the fade out problem remains unresolved:

 <div className= {mealOne_box ? 'meal_popup': 'meal_popup hidden'}>
                    <div className={box_transition ? 'meal_popupElement open' : 'meal_popupElement'}>
                        <CancelIcon onClick={mealOneClickHandler} />
                        <img alt='' src={PancakeImage} />
                        <div className='text_scroll'>
                            <h2>Ingredients:</h2>
                            <p>{Math.round((mealOneCals * 0.45) / 3.64)}g of flour, 1.5 teaspoons of baking powder, {Math.round((mealOneCals * 0.2) / 3.68)}g of cocoa powder, water, calorie free sweetener,  {Math.round((mealOneCals * 0.05) / 0.67)}g of mixed berries  and {Math.round(((mealOneCals * 0.3) / 1.55) / 44)} medium eggs.</p>
                            <p>High protein and low calorie dense option: use  {Math.round((mealOneCals * 0.55) / 3.64)}g of flour and {Math.round((mealOneCals * 0.2) / 0.45)}ml of egg white instead(this is less calorie dense so you get more food for the same amount of calories along with it being much higher in protein).</p>
                            <h2>Method:</h2>
                            <p>Combine the flour, egg, baking powder, cocoa together in a bowl to make a thick batter(add sweetener to taste). Then add as much water required to give the batter a pourable consistency. Pre heat a good non-stick pan on medium heat with no oil, once up to heat pour in your batter and flip once ready. Once all pancakes are made serve with fruit on-top.</p>
                        </div>
                    </div>
                    <div onClick={mealOneClickHandler} className='meal_popupBackground' />
                </div>

CSS Styles

.meal_popup {
  position: fixed;
  display: flex;
  align-items: center;
  top: 0;
  width: 100%;
  height: 100%;
  z-index: 30;
}

.meal_popup.hidden{
  visibility: hidden;
}

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

Utilizing arrays dynamically to generate data for a bar chart display in JavaScript

I'm currently working on generating a bar stack graph using the chart.js JavaScript library. My JavaScript array contains the following data: 0: {labels: "01/01/2020 00:00:00", data: 7433, category: "A"} 1: {labels: "01/01/2020 00:00:00", data: 774, ...

What is the best way to conceal a set of buttons on the main page using vue.js?

I'm having trouble hiding a button-group on the main page. It should disappear when either the button moveTo(0) is clicked or when scrolling to the top of the page. show: function() { this.scrollTop = (window.pageYOffset !== undefined) ? windo ...

Deactivating a button if the input fields are blank using ReactJS

Hi there, I'm new to reactJS and recently encountered an issue with my code. Everything seems to be working fine except for the NEXT button not being disabled when text fields are empty. My expectation is that the NEXT button should only be enabled af ...

Prevent removal of h2 tag within a contenteditable segment

Can a section be made permanent within a contenteditable element to prevent user removal? I have an h2 tag inside a contentEditable div. I do not want the user to be able to edit the h2 tag, so I set contentEditable=false, but they can still select and de ...

checkbox revision

I'm attempting to update some text indicating whether or not a checkbox is checked. The issue is that when the checkbox is checked, the textbox disappears and the text takes its place. <form name="myForm" id="myForm"> <input type="checkb ...

How to use PHP and JavaScript to update a location marker on Google Maps

I'm new to web development and in need of some help, please. I have a code that is supposed to update the marker location with coordinates retrieved from a database. <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=AP ...

My current array is arr=[1,2,3,4]. I recently added an element to it using arr.push(5). Now I want to rearrange the array to be [5,4,3,2,1]. Any suggestions on how to achieve this

I currently have an array in the following format: var arr = [1,2,3,4] // Add another element to the array arr.push(5) // Now, arr = [1,2,3,4,5] I want to print my array as The elements in the array arr are: 5,1,2,3,4 When I use Arr.reverse(), it retu ...

When attempting to create, an error occurs: Uncaught TypeError: Unable to access properties of undefined (retrieving 'id')

In the process of creating a public prayer journal that allows users to include their favorite Bible verses, I encountered an issue while trying to add a prayer or verse. The error message "caught (in promise) TypeError: Cannot read properties of undefined ...

Guide on implementing a date selector for each button/option clicked using Vue.js

My experience with Vuejs is still fresh, and I've incorporated 3 buttons named chart1, chart2, and chart3. Whenever any of these buttons are clicked, I want a Date selection to appear in a radio type format. You can see an example below: https://i.ss ...

What are the best ways to create image animations on top of other images using CSS or JavaScript?

Imagine if the first image is in black and white, while the second one is colored. How can we make the black and white image change to color after a timeout period, with an animation similar to loading progress bars? Is this achievable using CSS or JavaScr ...

Unable to transmit an object using ExpressJS

Greetings. I am currently trying to comprehend ExpressJS. My goal is to send a simple object from the express server, but it only displays "cannot get" on the screen. app.get("/", (req, res, next) => { console.log("middleware"); const error = true; ...

Learn how to toggle the menu list visibility by clicking on a component in Vue

I seem to be having an issue with closing a menu item in vue and vuetify2. Here is the code snippet that I have: <v-menu transition="slide-y-transition" bottom left offset-y nudge-bot ...

Setting state dynamically in Typescript with ReactJS

Within my state, I have defined this interface: interface State { id: string; name: string; description: string; dimensionID: string; file: File | null; operator: string; isFormValid: boolean; filename: string; }; To handle changes, I&apo ...

Choosing an option from a dropdown menu does not trigger the execution of an AngularJS function through Selenium

Currently, I am attempting to create a Selenium test that involves selecting an item from 2 dropdown menus and then clicking a button. However, I have encountered an issue where the second dropdown menu is populated based on an angularjs call depending on ...

Is it possible for you to execute 2 procedures consecutively simply by clicking on a button?

My question is quite straightforward. I have two buttons: <button @click="getPartyLeader" class="btn btn-success">Get party leader</button> <button @click="saveParty" class="btn btn-success">Submi ...

Why is my array.sort statement in ReactJS not functioning properly?

This question has been puzzling me for ages, despite the fact that it has probably been answered countless times. I have an array called products that contains various product objects, each with properties like name, price, amount, store name, and image UR ...

The Angular Observable continues to show an array instead of a single string value

The project I am working on is a bit disorganized, so I will try to explain it as simply as possible. For context, the technologies being used include Angular, Spring, and Maven. However, I believe the only relevant part is Angular. My goal is to make a c ...

Use jQuery to display the first 5 rows of a table

I recently posted a query on show hide jquery table rows for imported xml data regarding how to toggle visibility of specific table rows using jQuery. Now, I am seeking advice on how to make the first 5 elements always visible within the same context. Belo ...

Troubleshooting material design CSS problem in AngularJS routing module

Attempting to incorporate material design with routing in angular js, but encountering issues with CSS design not working. Interestingly, when using bootstrap CSS, it functions properly. Check out the Plnker Demo here However, upon trying this approach, ...

Differences in line spacing can be observed between the INPUT and LABEL elements

What could be causing this unusual behavior when setting line-height to match font-size: While the height of label is 16px, the height of input is 18px... Why is that? If I adjust line-height: 18px or higher, the heights suddenly align. But why does this ...