Почему мои переходы между стилизованными компонентами не работают?

#css #reactjs #styled-components

Вопрос:

Я работаю над Next.js проект, в котором меню открывается нажатием кнопки «бургер». Для этого я переключаю класс на кнопку, и стили для этого класса используют компоненты стиля.

Когда я нажимаю на кнопку, она меняется, как и ожидалось, но когда я добавляю переход CSS, он все еще не анимирован. Я протестировал тот же код в ванильном HTML, и он хорошо работает.

Где я ошибся?

Это мой код:

Бургер js:

 <BurgerStyled
    onClick={() => setIsBurgerOpen(!isBurgerOpen)}
    className={BurgerOpen}
>
    <span />
    <span />
    <span />
</BurgerStyled>
 

Поведение при нажатии:

 const [isBurgerOpen, setIsBurgerOpen] = useState(false);
const BurgerOpen = isBurgerOpen ? "BurgerOpen" : "";
 

Стилизованный компонент:

 const BurgerStyled = styled.div`
    width: 32px;
    height: 21px;
    position: relative;

    span {
        position: absolute;
        left: 0;
        background-color: var(--gray);
        width: 100%;
        height: 3px;
        transition: all 0.3s ease;

        amp;:first-child {
            top: 0;
        }

        amp;:nth-child(2) {
            top: calc(50% - 3px / 2);
        }

        amp;:last-child {
            bottom: 0;
        }
    }

    amp;.BurgerOpen span {
        amp;:first-child {
            transform: rotate(45deg);
        }

        amp;:nth-child(2) {
            width: 0;
        }

        amp;:last-child {
            transform: rotate(-45deg);
        }
    }
`;
 

Спасибо за ваши ответы!

Комментарии:

1. Я думаю, что переход CSS работает только с hover селектором.

Ответ №1:

Вы можете передать свойство своему стилизованному компоненту следующим образом:

JSX:

 return (
  <BurgerStyled
    onClick={() => setIsBurgerOpen(!isBurgerOpen)}
    open={isBurgerOpen}
  >
    <span />
    <span />
    <span />
  </BurgerStyled>
);
 

Стиль:

 const BurgerStyled = styled(({ open, ...restProps }) => <div {...restProps} />)`
  ${({ open }) => open ? ` styles open here ` : ` styles closed here `};
`;
 

Что вы здесь делаете: вы передаете open реквизит своему стилизованному компоненту, а затем передаете все остальные реквизиты в div. open Реквизит теперь доступен в строке шаблона вашего стиля. Это предотвращает open передачу реквизита в DOM-элемент, поскольку <div> DOM-элемент не имеет open свойства, поэтому передача его в DOM приведет к появлению предупреждений.

Ответ №2:

Вы можете попробовать svg и перейти, чтобы получить желаемый результат. Проверьте мой пример кода ниже, это может вам помочь.

   import { motion } from './framer-motion'; //install it with npm     
  
  const [isBurgerOpen, setIsBurgerOpen] = useState(false);
  const HamburgerMenuContainer = styled.div`
     display:flex;
  `;

  const MenuContainer = styled.div`
  min-width:300px;
  width:100%;
  max-width:44%;
  height:100%;
  background-color: #fff;
  box-shadow: -2px 0 2px rgba(15,15,15,0.3);
  z-index:90;
  position:fixed;
  top:0;
  right:0;
  user-select:none;
  padding: 1em 2.5em;
  `;

  const Button = styled.button`
  z-index:99;
  cursor:pointer;
  `;
  
  const Path = props =>{
    <motion.Path fill="transparent" strokeLinecap="round" strokeWidth="3" {...props}/>
  }

const transition = {duration: 0.3};
  return (
    <>
      <HamburgerMenuContainer>
        <Button onClick={() => setIsBurgerOpen(true)}>
        <svg width="23" height="23" viewBox="0 0 23 23">
          <Path animate={isBurgerOpen ? "open" : "closed"} initial={false} variants={{
            closed: {d: "M 2 2.5 L 20 2.5",stroke:"hsl(0, 0%, 100%)"},
            open: {d: "M 3 16.5 L 17 2.5",stroke:"hsl(0, 0%, 18%)"},
          }} 
          transition={transition}
          />
          <Path animate={isBurgerOpen ? "open" : "closed"} initial={false} variants={{
            closed: {d: "M 2 2.5 L 20 2.5",stroke:"hsl(0, 0%, 100%)"},
            open: {d: "M 3 16.5 L 17 2.5",stroke:"hsl(0, 0%, 18%)"},
          }} 
          transition={transition}
          />
          <Path animate={isBurgerOpen ? "open" : "closed"} initial={false} variants={{
            closed: {d: "M 2 2.5 L 20 2.5",stroke:"hsl(0, 0%, 100%)"},
            open: {d: "M 3 16.5 L 17 2.5",stroke:"hsl(0, 0%, 18%)"},
          }} 
          transition={transition}
          />
        </svg>
        </Button>
      </HamburgerMenuContainer>
      </>
  );
}
 

Ответ №3:

Я мог бы решить эту проблему. Мой компонент гамбургера был за пределами заголовка, вот так:

 function Header() {
    const Burger = () => {
        // Burger component
    }

    return (
        <Burger />
    )
}
 

Я просто сформулировал это так, и это сработало:

 function Header() {
    return (
        <BurgerStyled ...>
            <span />
            <span />
            <span />
        </BurgerStyled>
        // Content header
    )
}
 

Теперь анимация работает, спасибо за ваши ответы!