Помогите с анимацией React-компонента. Не работает transition

Задача просто до безобразия: При клике на кнопку burger должен открываеться сайдбар с навигацией. Функционал сделал, но не работает анимация. Задаю ее через transition в css свойствах компонента, но он не работает. Подскажите что делать, весь день убил, чтобы понять в чем дело.

JS-код:

function Header() {
    const [isMenuActive, setMenuActive] = useState(false);

    const togle = ()=> setMenuActive(!isMenuActive);

    // кнопка открытия меню
    function OpenMenuBtn() {
        return (
            <button onClick={togle} className='menu-btn'>
                <img className='menu-img' src="./images/menu-ico.svg" alt="" />
            </button>
        );
    }

    // кнопка закрытия меню
    function CloseMenuBtn() {
        return (
            <button onClick={togle} className='close-menu-btn'>X</button>
        );
    }

    // компонент сайбара
    function MenuNav() {
        return (
            <div className = {isMenuActive ? 'menu active' : "menu"}>
                <div className="header__nav">
                    <CloseMenuBtn />
                    <p className='header__nav-link' href="#">Home</p>
                    <p className='header__nav-link' href="#">About</p>
                    <p className='header__nav-link' href="#">Services</p>
                    <p className='header__nav-link' href="#">Gallery</p>
                </div>
            </div>
        );
    }

    return (
        <div className='header'>
            <div className='container'>
                <div className="header__inner">
                    <OpenMenuBtn />
                    <MenuNav />
                </div>
            </div>
        </div>
    );
}

export default Header;

SCSS:

 .menu {
            background: rgba(0, 0, 0, 0.13);
            position: absolute;
            transform: translateX(-100%);
            left: 0px;
            top: 0px;
            width: 100%;
            height: 100vh;
            transition: 0.3s all;
        }

        .menu.active{
            transition: 0.3s all;
            transform: translateX(0px);
        }


        &__nav {
            padding: 20px;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            height: 100%;
            width: 250px;
            background-color: rgb(253, 238, 220);

            &-link {
                margin-right: 0px;
                margin-bottom: 30px;
            }
        }

Предполагаю, что после изменения состояние реакт рендерит новый компонент навигации меню с классом, подходящим под условие с заданным стейтом. Тогда возникает очевидный вопрос, как применить анимацию к компоненту реакт?

Очень прикольная ситуация. Побился об эту задачу. Единственный вывод что когда компоненты создаются вне Header, код работает, но механика общего стейта теряется. Похоже что тебе придется решать задачу через вынос общего стейта в контекст (я сам не сварщик, не знаю механик современного реакте) чтобы объявить компоненты вне общего. А такая удобная была задумка…

Я тут поменял логику как объявляются компоненты и кто триггерит изменение стейта (кликай по самому контенту). Анимации срабатывают.


PS. Когдай найдешь решение расскажи словам в чем оно заключается. Интересная ситуация.

Нужно было просто вынести компонент MenuNav в отдельный компонент и передавать в него функцию изменения стейта в качестве пропса. React сравнивает виртуальный DOM и нативный, а затем реререндерит тот компонент, который изменился. В нерабочем варианте выше у меня ререндерился блок header__inner целиком( следил ща изменениями классов в DevTools браузера), так как все дочерние компоненты описывались внутри родительского компонента Header. Когда менялся стейт Header, происходил ререндеринг всего этого компонента целиком.
Вынос дочерних компонентов оптимизировал код и как итог изменение стейта меняет только атрибут класаа в MenuNav

Рабочий вариант кода:

import './header.scss';
import React from 'react';
import { useState } from 'react';

function MenuNav(props) {

    // кнопка закрытия меню
    function CloseMenuBtn() {
        return (
            <button onClick={props.togle} className='close-menu-btn'>X</button>
        );
    }

    return (
        <div className={props.isMenuActive ? 'menu active' : "menu"}>
            <div className="header__nav">
                <CloseMenuBtn />
                <p className='header__nav-link' href="#">Home</p>
                <p className='header__nav-link' href="#">About</p>
                <p className='header__nav-link' href="#">Services</p>
                <p className='header__nav-link' href="#">Gallery</p>
            </div>
        </div>
    );
}

// кнопка открытия меню
function OpenMenuBtn(props) {
    return (
        <button onClick={props.togle} className='menu-btn'>
            <img className='menu-img' src="./images/menu-ico.svg" alt="" />
        </button>
    );
}

function Header() {
    const [isMenuActive, setMenuActive] = useState(false);

    const togle = () => setMenuActive(!isMenuActive);

    return (
        <div className='header'>
            <div className='container'>
                <div className="header__inner">
                    <OpenMenuBtn togle={togle} />
                    <MenuNav isMenuActive={isMenuActive} togle={togle} />
                </div>
            </div>
        </div>
    );
}

export default Header;
.menu {
            background: rgba(0, 0, 0, 0.13);
            position: absolute;
            transform: translateX(-100%);
            left: 0px;
            top: 0px;
            width: 100%;
            height: 100vh;
            transition: all 0.3s;
        }

        .menu.active{
            transition: all 0.3s;
            transform: translateX(0px);
        }


        &__nav {
            padding: 20px;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            height: 100%;
            width: 250px;
            background-color: rgb(253, 238, 220);

            &-link {
                margin-right: 0px;
                margin-bottom: 30px;
            }
        }
1 лайк

Надо было просто открыть документацию и покопаться в разделе рендеринга компонентов