React transition for overlaying a navigation bar

I'm encountering an issue with an overlay navbar that should slide in from the top.

For some reason, when I click the hamburger menu, the correct CSS class is applied but the transition doesn't happen (it behaves like a show/hide effect). However, if I manually change the 'top' property value using the dev tools, it works as intended.

What could be causing this behavior?

Here's the React component code:


import React, { useState } from "react";
import NavMenuIcon from "../../public/svg/nav.svg";
import styles from '../../styles/Navbar.module.scss'
import Link from 'next/link'

function Navbar() {
    const [menu, setToggle] = useState(false);
    const toggleMenu = () => setToggle(!menu);

    const Menu = props => (
        <div className={ props.toggle ? `${styles.menu__container} ${styles.toggle}` : `${styles.menu__container}` }>
          <div className={styles.menu__content}>
            <ul className={styles.menu__list}>
              <li className={styles.menu__item} onClick={toggleMenu}> <Link href="/"><span>Home</span></Link></li>
              <li className={styles.menu__item} onClick={toggleMenu}> <Link href="/services"><span>Services</span></Link></li>
              <li className={styles.menu__item} onClick={toggleMenu}> <Link href="/services#contact"><span>Contact</span></Link></li>
            </ul>
          </div>
        </div>
    );

    return (
      <div className={styles.navbar}>
        <i>Meuartelie</i>
        <NavMenuIcon className={styles.hamburger} onClick={toggleMenu} />
        <Menu toggle={menu}></Menu>
      </div>
    );
}

export default Navbar;

And here's the corresponding CSS:

@import './variables.scss';

.navbar {
  box-sizing: border-box;
  position: fixed;
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 5%;
  z-index: 5;
}

.menu__container {
  font-family: 'Jokerman Std';
  position: absolute;
  top: -300px;
  left: 0;
  width: 100vw;
  height: 300px;
  z-index: -1;
  background-image:  url("../public/png/welcome_mobile.png");
  background-color: black;
  background-size: cover;
  overflow: hidden;
  transition: 850ms;
}

.menu__content {
  font-size: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 20%;
}

.menu__container.toggle {
  top: 0;
  transition: all 1s ease-in;
}

.menu__list {
  width: 80%;
  text-align: center;
  list-style: none;
  padding: 0px;
  line-height: 2;
  margin: 0px;
  margin-bottom: 20px;
}

.menu__item {
  transition: padding-left .7s ease, color .7s ease;
  /* underline css*/
  text-decoration: none; 
  position: relative; 
}

.menu__item:hover {
  color: $base-color;
  padding-left: 20px;
  cursor: pointer;
}


.menu__item:after {
  content: '';
  height: 2px;
  /* adjust this to move up and down. you may have to adjust the line height of the paragraph if you move it down a lot. */
  bottom: 0px; 
  /* center - (optional) use with adjusting width   */
  margin: 0 auto;
  left: 0;
  right: 0;
  width: 40%;
  background: #fff;
  /* optional animation */
  -o-transition:.5s;
  -ms-transition:.5s;
  -moz-transition:.5s;
  -webkit-transition:.5s;
  transition: .5s;
}
     

/* optional hover classes used with anmiation */
.menu__item:hover:after {
  background: $base-color;
}

.hamburger {
  z-index: 1000;
  cursor: pointer;
}

Answer №1

React's rerendering process is based on detecting new references in the render tree, prompting automatic re-renders for those elements.
In contrast, CSS transitions transition from one state to another; if the start and end states are the same, no transition occurs.

Here's what really happens:

  1. A button click triggers
  2. The render tree is modified with a new reference assigned to const Menu
  3. Old elements are removed from the DOM, like
    <div class="menu__container">
  4. New elements are added to the DOM, such as
    <div class="menu_container toggle">
  5. The browser renders the element applying initial CSS rules; top:0 serves as the initial state without transition due to the removal of the old element.

How to resolve it:
Ensure React recognizes that the same element is being rendered to update the existing DOM element rather than adding/removing a new one.
Various methods can achieve this, with extracting the component from the render function being the recommended approach for maintaining a static reference.

//extracted from render function:
const Menu = (props) => (
  <div key='1' className={ props.toggle ? `menu__container toggle` : `menu__container` }>
    <div className={'menu__content'}>
      <ul className={'menu__list'}>
        <li className={'menu__item'} onClick={props.toggleMenu}> <Link href="/"><span>Home</span></Link></li>
        <li className={'menu__item'} onClick={props.toggleMenu}> <Link href="/services"><span>Services</span></Link></li>
        <li className={'menu__item'} onClick={props.toggleMenu}> <Link href="/services#contact"><span>Contact</span></Link></li>
      </ul>
    </div>
  </div>
);


function Navbar() {
  const [menu, setToggle] = useState(false);
  const toggleMenu = () => setToggle(!menu);
 
  return (
    <div className={'navbar'}>
      <i>Meuartelie</i>
      <button className={'hamburger'} onClick={toggleMenu} >☰</button>
      <Menu toggle={menu} toggleMenu={toggleMenu}></Menu>
    </div>
  );
}

Situations may arise where extracting the component isn't feasible, especially when components are dynamically created/determined.
In such cases, the hook useMemo comes in handy to instruct React to store the reference and only recalculate if a prop in the dependency array changes.

function NavbarAndMenuMemoized() {
  const [menu, setToggle] = useState(false);
  const toggleMenu = () => setToggle(!menu);
 
  // useMemo retains the same reference for Menu instead of recalculating each render.
  const Menu = useMemo(()=>{
    return(props) => (
      <div key='1' className={ props.toggle ? `menu__container toggle` : `menu__container` }>
        <div className={'menu__content'}>
          <ul className={'menu__list'}>
            <li className={'menu__item'} onClick={toggleMenu}> <Link href="/"><span>Home</span></Link></li>
            <li className={'menu__item'} onClick={toggleMenu}> <Link href="/services"><span>Services</span></Link></li>
            <li className={'menu__item'} onClick={toggleMenu}> <Link href="/services#contact"><span>Contact</span></Link></li>
          </ul>
        </div>
      </div>
    );
  }, [])

  return (
    <div className={'navbar'}>
      <i>Meuartelie</i>
      <button className={'hamburger'} onClick={toggleMenu} >☰</button>
      <Menu toggle={menu} ></Menu>
    </div>
  );
}

Check out live demo Example here

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

Modify the SVG height using JavaScript and CSS

In my SVG file, I have paths for all the countries in the world. Each country is represented by its own individual path like this: <path inkscape:connector-curvature="0" id="PH" data-name="Philippines" data-id="PH" d="m 16 ...

the state hooks are failing to update the state when there is a change

Struggling with updating the title of my blog in a simple blog app. The current state is not being updated despite multiple attempts to change the method of setting state. Here's a snippet from App.js: function BlogDetail() { const [blogName, set ...

Navigation in PHP webpages and determining the active page

In my template.php file, I am including navigation.php from a separate page. My goal is to have the current page highlighted with a specific CSS style as I navigate through different pages on my website. I want the active link to be dynamically styled base ...

Guide to adding an additional border within a div element

In my HTML document, I've created a div element with a border: .box {border: 1px solid black; width: 100%; height: 200px} <div class="box"></div> Now, I'm looking to enhance this div by adding a second vertical line that will divid ...

Unable to utilize container-fluid on Chrome and tablet-sized screen due to compatibility issues

By using the container-fluid class, I have created a header that spans the entire front page. While this setup functions perfectly on Opera, Firefox, and Microsoft Edge, it falls short on Chrome, iPad, and mobile phone screens. Take a look at my code: &l ...

Leveraging flask/jinja for incorporating dynamic content without the need for an HTML table

Although I'm not well-versed in web development, I hope this question is on the right track. In my flask app, I'm trying to create a section that showcases albums/cards in a similar style as seen on this example. My goal is to display multiple ...

Storing and retrieving cookies in ReactJS for data persistence

Having recently started working with cookies in React JS, I encountered an issue with the following code snippet. console.log(this.state.datasets); cookie.save('datasets', this.state.datasets, { path: '/' , 'maxAge': 100000}) ...

Is it possible to extract the CSS path of a web element using Selenium and Python?

I am working with a collection of elements using find_elements_by_css_selector, and my next task is to extract their css locators. I attempted the following approach: foo.get_property('css_selector') However, it seems to be returning None. ...

Does combining react-bootstrap with plain bootstrap create a negative outcome?

Currently, our team project involves a combination of react-bootstrap 1.0.0 and bootstrap 4.3.1's css+js. This has led to a divided approach within the team - some developers lean towards using react-bootstrap components while others prefer styling el ...

How can I align icons to the right and display text below each one?

I need to display icons with their names below them in a row from left to right, with proper spacing. Each icon should have its name displayed underneath it, for example "Icon1" under icon1 and so on. The tierGo element does not contain any CSS styles. ...

Ways to update the icon in reactstrap dropdown menu?

Is there a way to customize the default dropdown icon in reactstrap with my own image icon? import React, { useState } from 'react'; import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap'; const Example = (p ...

Element with absolute positioning inside a relative parent does not interfere with other elements outside of the parent

I am currently facing a challenge with a simple dialog that is positioned absolutely in the center of the screen. Inside this dialog, there is a dropdown with a relatively positioned parent (I want the dropdown to follow its parent's position without ...

Deploying ReactJS on a local server: A step-by-step guide

My web app is built with a NodeJS + Express + GraphQL + MongoDB backend and a ReactJS + Apollo frontend. I am interested in deploying this application locally. Is it feasible to do so? I have come across numerous tutorials on how to deploy to platforms li ...

What could be causing the defaultOpen feature to function on my code simulator but fail to work on my website?

I have a set of tabs on my website, and I want the first tab to be automatically selected when the page loads. I tried using some Javascript code from w3schools, which worked in a simulator, but now it's not working on my actual site, and it looks ter ...

What is the best way to create separate arrays for every element in my object, containing a total of four arrays to efficiently produce a weekly forecast?

Hey there, I'm back with an update on my ongoing project. I've encountered a major challenge while trying to incorporate a 7-day forecast display in my app. Something along these lines: https://i.stack.imgur.com/xJA4M.png https://i.stack.imgur. ...

How can data be transferred from props to state in React Native?

I'm facing a problem with my homescreen button that is supposed to toggle the text in the AlertBar. When I click the button, the text in AlertBar should change based on the status of isParked. However, currently nothing happens when I press the butto ...

Changing between two images using HTML and CSS

I am currently designing a WordPress theme and I would like to create an effect where two different thumbnail images switch on hover. The code that I have come up with so far looks something like this : <a class="thumb" href="posturl"> <img src= ...

Tips for bypassing index.d.ts files when searching for definitions

Recently, I set up a webpack alias in my jsconfig.json file specifically for use with VSCode. However, when attempting to navigate to the definition of a React component, I am presented with two different definitions: The definition of my specific React ...

Is it possible in JQuery for the mouseup event to not be triggered if the left click button is held down for 10 seconds and then released suddenly, causing the mouse to move too quickly?

How to Move a DIV Inside Another Parent DIV Using Mouse Events in jQuery $(document).ready(function () { var drag = null; var Top = null; var Left = null; var O = $("#Outside").offset(); var outside ...

Vertical table header in ASP.NET MVC 5

Can anyone recommend how to reposition Headers from the top to the left column vertically? I would also like to know if there are any jQuery plugins available for directly editing tables from a grid with examples :) Since I am new to this... <table c ...