Styled components onClick rotate element

2.3k Views Asked by At

I'm trying to add a rotation to an element when clicked. Each time I want to click on the element the element should rotate. I'm rotating the element using CSS transform property. Bellow is my styled component:

const IconButtonWrapper = styled.div`
  transform: rotate(0deg);
  overflow: hidden;
  transition: all 0.3s ease-out;
  ${({ rotate }) => rotate && `transform: rotate(360deg)`};
`;

And I have the React component that renders the element and has the onClick event:

const IconButtonContainer = () => {
  const [rotate, setRotate] = useState(false);

  const handleClick = () =>
    setRotate(
      (prevState) => ({ rotate: !prevState.rotate }),
      () => console.log(this.state.rotate)
    );

  return (
    <IconButtonWrapper rotate={rotate} onClick={handleClick}>
      <IconButton />
    </IconButtonWrapper>
  );
};

When I click the first time everything works as expected, but when I click the second time, doesn't work anymore. I feel I should return to default state rotate: false after the transition, but how do I do that in styled components?

Here is a link to a working Sandbox

3

There are 3 best solutions below

0
On BEST ANSWER

Technically rotate is already a boolean so prevState should be a boolean as well. Also you were trying to set an object to the rotate state value instead of a simple boolean.

Based on that you only need to negate prevState and not prevState.rotate as:

setRotate(prevState => !prevState)

See the code modification from !prevState.rotate to !prevState.

Also suggested read is Using the State Hook. It's a bit different than class components.

0
On

Try this out.

const handleClick = () => setRotate(!rotate);
0
On

The problem is solving by changing the code of handleClick to:

import React, { useState } from "react";
import ReactDOM from "react-dom";
import styled from "styled-components";

import "./styles.css";

const IconButton = () => <button>Icon</button>;

const IconButtonWrapper = styled.div`
  transform: rotate(0deg);
  overflow: hidden;
  transition: all 0.3s ease-out;
  ${({ rotate }) => rotate && `transform: rotate(360deg)`};
`;

const IconButtonContainer = () => {
  const [rotate, setRotate] = useState(false);

  const handleClick = () => setRotate((prevState) => (!prevState ));
  return (
    <IconButtonWrapper rotate={rotate} onClick={handleClick}>
      <IconButton />
    </IconButtonWrapper>
  );
};

function App() {
  return (
    <div className="App">
      <IconButtonContainer />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

prevState already has the latest value of rotate but you were converting it to an object. setRotate((prevState) => (!prevState )); will do.