Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

216
Visualizações
How to animate change of colour (keyframes) forward and back on click with useState without starting animation during first loading of page?

I got a little tricky problem.

I am having a container with is being coloured on clicking it. Clicking it will result in sending data to array, but thats not the problem.

Clicking it will also animate the change of colour. Animation will be triggered forward on click, and backwards if container will be clicked again.

The issue is that animation is triggered conditionally with use of useState (boolean) and thus, the second animation will be running already when page is loaded, before even clicking the container. I was wondering about animation-play-state style, but it not seems to be sufficient.

Heres the editable demo https://qeevsk.csb.app/ Any ideas, maybe there is better aproach ?

The code itself:

    const [activeDiv, setDivState] = useState(false);
    
      const BigDiv = styled("div")(
        ({ theme, activeDiv }) => css`
          min-width: 220px;
          height: 100%;
          position: relative;
          padding: ${theme.spacing(2, 0)};
          border-bottom: red 4px solid;
          background-color: transparent;
          cursor: pointer;
          text-align: center;
          transition-delay: 0.5s;
        will-change: transform;

    ::after {
      content: '';
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-color: ${activeDiv ? "red" : "transparent"};
      animation: ${activeDiv ? setColor("red") : unsetColor("red")}
        0.5s ease ;
      transform-origin: bottom center};
    }

    `
  );

  const setColor = (colorTo) => keyframes` 
  0% {transform: scaleY(0); }
  100% {transform: scaleY(1); background-color: ${colorTo}} 
`;
  const unsetColor = (colorFrom) => keyframes`
  0% {transform: scaleY(1); background-color: ${colorFrom}}
  100% {transform: scaleY(0); background-color: transparent;}
 
`;

  const SecondDiv = styled("div")(
    ({ theme, activeDiv, color }) => css`
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      text-align: center;
      position: relative;
      z-index: 1;
    `
  );

  return (
    <>
      <BigDiv
        activeDiv={activeDiv}
        onClick={(e) => {
          setDivState(!activeDiv);
        }}
      >
        <SecondDiv>
          <p>Click to animate</p>
        </SecondDiv>
      </BigDiv>
    </>
  );
}
about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

You got some valid answers already, but if you're looking for a different approach you could manage the animation state with a third value like "IDLE":

const AnimStatus = {
  IDLE: -1,
  INACTIVE: 0,
  ACTIVE: 1
};

// the status will be handled like this:
const [divStatus, setDivStatus] = useState(AnimStatus.IDLE);

  <BigDiv
    divStatus={divStatus}
    onClick={(e) => {
      setDivStatus((prev) =>
        prev === AnimStatus.INACTIVE || prev === AnimStatus.IDLE
          ? AnimStatus.ACTIVE
          : AnimStatus.INACTIVE
      );
    }}
  />
  
// in the css animation
const BigDiv = styled("div")(
  ({ theme, divStatus }) => css`
    /* BigDiv CSS properties */

  ::after {
  /* Other ::after CSS properties */
    width: 100%;
    height: 100%;
    transform-origin: bottom center;
    ${
      divStatus !== AnimStatus.IDLE
        ? css`
            background-color: ${divStatus === AnimStatus.ACTIVE
              ? "red"
              : "transparent"};
            animation: ${divStatus === AnimStatus.ACTIVE
                ? setColor("red")
                : unsetColor("red")}
              0.5s ease;
          `
        : ""
    }
  };
}
  `
);

   

The advantage of this approach is that you can reuse this AnimStatus across all your animations as an interface, and easily add specific effects for "IDLE"

Here is my demo: https://codesandbox.io/s/animate-divs-forked-u2oltp

about 4 years ago · Juan Pablo Isaza Relatório

0

You can define a state variable something like startAnimation and set to to false by default.

When user click on click it to continue then set it to true and apply animation accordingly

Defined state

const [startAnimation, setStart] = useState(false);

Pass it in component

<BigDiv
        activeDiv={activeDiv}
        startAnimation={startAnimation}
        onClick={(e) => {
          setStart(true);
          setDivState(!activeDiv);
        }}
      >
        <SecondDiv>
          <p>Click to animate</p>
        </SecondDiv>
      </BigDiv>
    </>

Use it in component like this

const BigDiv = styled("div")(
    ({ theme, activeDiv, startAnimation }) => css`
      min-width: 220px;
      height: 100%;
      position: relative;
      padding: ${theme.spacing(2, 0)};
      border-bottom: red 4px solid;
      background-color: transparent;
      cursor: pointer;
      text-align: center;
      transition-delay: 0.5s;
    will-change: transform;

    ::after {
      content: '';
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-color: ${activeDiv ? "red" : "transparent"};
      animation: ${
        startAnimation ? (activeDiv ? setColor("red") : unsetColor("red")) : ""
      }
        0.5s ease ;
      transform-origin: bottom center};
    }

    `
  );
about 4 years ago · Juan Pablo Isaza Relatório

0

Easiest fix I could think of was to set the initial activeDiv state to null and change the animation rule to:

animation: ${activeDiv ? setColor("red") : unsetColor("red")} ${activeDiv === null ? "0" : "0.5s ease"} ;

Now there won't be any animation at startup, but it will animated if activeDiv is anything but null.

Here is my fork: https://codesandbox.io/s/animate-divs-forked-gth814

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda