Home > Software engineering >  I want the arrow icon to flip up and down every time the state changes.and I want to animate it
I want the arrow icon to flip up and down every time the state changes.and I want to animate it

Time:10-21

I am using react, styled-components.
When state(visible) is set to true, DropMenu box1 and box2 will be displayed.
We want the ArrowDown icon to flip upward when state is true, and downward when false.
I also want to apply an animation when flipping it.
I want to add an animation like the Dropdown in the following site.  

Reference site

code

import "./styles.css";
import styled from "styled-components";
import React, { useState, useCallback } from "react";
import { ArrowDown } from "./ArrowDown";

const Item = styled.div<{ active?: boolean }>`
  height: 40px;
  width: 300px;
  padding: 0px 30px;

  &:hover {
    background: #fafbfb;
  }
`;

const DropMenu = styled.div`
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: #899098;
  width: 100%;
  height: 100%;
  font-size: 14px;
  font-weight: bold;
  gap: 12px;
  :hover {
    color: gray;
  }
  div {
    display: flex;
    align-items: center;
    gap: 12px;
  }
`;

const DropText = styled.div`
  padding-left: 32px;
`;

export const App = () => {
  const [visible, setVisible] = useState(false);
  const handleDropVisibleChange = useCallback(() => {
    setVisible((prevVisible) => !prevVisible);
  }, [visible]);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <Item onClick={handleDropVisibleChange}>
        <DropMenu>
          <div>
            <span>Menu</span>
          </div>
          <ArrowDown />
        </DropMenu>
      </Item>
      {visible && (
        <div style={{ transition: "all 0.5s ease" }}>
          <Item>
            <DropMenu>
              <DropText>box1</DropText>
            </DropMenu>
          </Item>
          <Item>
            <DropMenu>
              <DropText>box2</DropText>
            </DropMenu>
          </Item>
        </div>
      )}
    </div>
  );
};

export default App;

CodePudding user response:

TLDR

  1. Change your MenuItem component warpper to something like
const DropMenuWrapper = styled.div<{ visible: boolean }>`
  transition: all 0.5s ease;
  opacity: ${(props) => (props.visible ? 1 : 0)};
`;
  1. replace the visibility switch mechanism with following
- {visible && (
-     <div style={{ transition: "all 0.5s ease" }}>

      <DropMenuWrapper visible={visible}>

similar action can be added to the arrow-down icon also with style (The ArrowDown SVG icon must accept style if it is custom written component)

<ArrowDown
  style={{
    transition: "all 0.5s ease",
    transform: `rotate(${visible ? 0 : "0.5turn"})`
  }}
/>

Why this happened:

When a component (sub-component/element) is mounted in react, it starts a complete life cycle toward browser paint. So it is must have the property which causes the element to animate, for example, I added the opacity transition to the example itself, forcing it to animate in the first look and in disappearing.

Although it comes with some performance cost of having unseen elements still in the dom (but not visible), making it bad for accessibility too, it is the simplest way to achieve this behavior.

Consider this example If you have an animated element, does it show the animation if you refresh the browser if the answer is yes, it will show animation in react too.

Another way of doing some animation in react.

In this case you can also trigger the end event and start to unmount the component as the animation disappears and end completely.

If you want to take your understanding of what is needed for the transition when the component is unmounted and removed from aka dom, I highly encourage you to read the animation section of svelte docuementation

  • Related