Search code examples
reactjsstyled-components

React: state updates only once on click


I am trying to rotate an hour arrow on click on my clock and can't understand why does clicking happens only once. Could you please me suggest another way to do it, if possible

I need to animate this property by dynamically passing deg props into styled components like this.

transform: ${props => (props.deg && `rotate(${props.deg}deg)`)};

enter image description here

import React, { useRef, useState, useEffect } from 'react';
import styled from 'styled-components';

const Clock = styled.div`
  width:100%;
  height:100%;
  display:flex;
  justify-content:center;
  align-items:center;
  background:#fff url('https://res.cloudinary.com/nzmai/image/upload/v1602513284/be-verb-diagram/clock.png');
  background-size:cover;
  border-radius:50%;
  border:2px solid #fff;
  box-shadow:inset 0 0 30px rgba(0,0,0,0.1), 0 20px 20px rgba(0,0,0,0.2), 0 0 4px rgba(255,255,255,1);
  &::before {
    content:'';
    position:absolute;
    width:15px;
    height:15px;
    background:#848484;
    border:2px solid #fff;
    z-index:10000;
    border-radius:50%;
  }
`;

const Hour = styled.div`
  position:absolute;
  width:160px;
  height:160px;
`;

const Hr = styled.div`
  display:flex;
  justify-content:center;
  border-radius:50%;
  position:absolute;
  width:160px;
  height:160px;
  transition: all 0.3s ease-out;
  transform: ${props => (props.deg && `rotate(${props.deg}deg)`)};
  &:before {
    content:'';
    position:absolute;
    width:8px;
    height:80px;
    background:#848484;
    z-index:10;
    border-radius:6px 6px 0 0;
  }
`;

const Minute = styled.div`
  position:absolute;
  width:190px;
  height:190px;
`;

const Mn = styled.div`
  display:flex;
  justify-content:center;
  border-radius:50%;
  position:absolute;
  width:190px;
  height:190px;
  &:before {
    content:'';
    position:absolute;
    width:4px;
    height:90px;
    background:#d6d6d6;
    z-index:11;
    border-radius:6px 6px 0 0;
  }
`;

function AnalogueClock() {
  const [hourArrowRotation, setHourArrowRotation] = useState(0);
  

  console.log(hourArrowRotation)

  return (
    <Clock>
      <Hour>
        <Hr id="hr" deg={ hourArrowRotation } onClick={ () => { 
          setHourArrowRotation(hourArrowRotation + 30)
        } }></Hr>
      </Hour>
      <Minute>
        <Mn></Mn>
      </Minute>
    </Clock>
  );
}

export default AnalogueClock;

Solution

  • This is because the minute div is overlapping the hour div and since both are absolute the hour div will be rendered behind the minute div. That means if you click on Hr, which is inside Hour, the minute div will capture it even if you don't have an onClick function assigned to minute div.

    One of the way to disable the click using pointer-events:none style for Minutes, here is an example

    const Minute = styled.div`
      position:absolute;
      width:190px;
      height:190px;
      pointer-events:none 
    `;