kyun
kyun

Reputation: 10264

Dynamic css animation variable with React

const {useState, useEffect, useRef} = React;
const App = () => {
  const [pressed, setPressed] = useState(false);
  const [shoot, setShoot] = useState(false);
  const [seconds, setSeconds] = useState(0);
  useInterval(() => {
    // Your custom logic here
    pressed && seconds < 3 && setSeconds((prev)=> Number((prev+0.1).toFixed(1)));
  }, 100);
  
  useInterval(()=>{
    !pressed && seconds > 0 && setSeconds((prev)=>{
      if( Number((prev-0.5).toFixed(1)) < 0){
        return 0;
      }
      return Number((prev-0.5).toFixed(1))
    });
  }, 20)
  return (
    <div>
      <button
        onMouseDown={()=>{
          console.log('mouseDown')
          setShoot(false);
          setPressed(true);
        }}
        onMouseUp={()=>{
          console.log('mouseUp')
          setShoot(true);
          setPressed(false);
        }}
        style={{
          transform: `rotate(-${seconds*15}deg)`
        }}
      >Press</button>
      <span className={`dot ${shoot ? '--shooted' : ''}`} />
      <p>{seconds}</p>
    </div>
  )
};
ReactDOM.render(<App />, document.getElementById('root'));

function useInterval(callback, delay) {
  const savedCallback = useRef();

  // Remember the latest callback.
  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  // Set up the interval.
  useEffect(() => {
    function tick() {
      savedCallback.current();
    }
    if (delay !== null) {
      let id = setInterval(tick, delay);
      return () => clearInterval(id);
    }
  }, [delay]);
}
.dot{
  position: absolute;
  width: 16px;
  height: 16px;
  border-radius:100%;
  background: red;
}

.dot.--shooted{
  animation: test 1s;
}

@keyframes test{
  0%{
    transform: translateX(0px);
  }
  100%{
    transform: translateX(200px); // it should be dynamic px.
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.26.0/moment.min.js"></script>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root" />

I'd like to move the red dot as much as the seconds I pressed the button.

but I am using animation so I can't control the px in CSS.

If I pressed the button for 3seconds, the red dot should be moved to 300px.

If I pressed the button for 1seconds, the red dot should be moved to 100px.

Upvotes: 1

Views: 2362

Answers (1)

demkovych
demkovych

Reputation: 8817

This is an example. But you need to add a logic to move it back.

const {
  useState,
  useEffect,
  useRef
} = React;
const App = () => {
  const [pressed, setPressed] = useState(false);
  const [shoot, setShoot] = useState(false);
  const [seconds, setSeconds] = useState(0);
  const dotRef = useRef();

  useInterval(() => {
    // Your custom logic here
    pressed && seconds < 3 && setSeconds((prev) => Number((prev + 0.1).toFixed(1)));
  }, 100);

  useInterval(() => {
    !pressed && seconds > 0 && setSeconds((prev) => {
      if (Number((prev - 0.5).toFixed(1)) < 0) {
        return 0;
      }
      return Number((prev - 0.5).toFixed(1))
    });
  }, 20)

  const handleMouseUp = () => {
    dotRef.current.style.transform = `translateX(${seconds * 100}px)`;
  }

  return ( <
    div >
    <
    button onMouseDown = {
      () => {
        console.log('mouseDown')
        setShoot(false);
        setPressed(true);
      }
    }
    onMouseUp = {
      () => {
        console.log('mouseUp')
        setShoot(true);
        setPressed(false);
        handleMouseUp();
      }
    }
    style = {
      {
        transform: `rotate(-${seconds*15}deg)`
      }
    } >
    Press < /button> <
    span className = {
      `dot ${shoot ? '--shooted' : ''}`
    }
    ref = {
      dotRef
    }
    /> <
    p > {
      seconds
    } < /p> < /
    div >
  )
};
ReactDOM.render( < App / > , document.getElementById('root'));

function useInterval(callback, delay) {
  const savedCallback = useRef();

  // Remember the latest callback.
  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  // Set up the interval.
  useEffect(() => {
    function tick() {
      savedCallback.current();
    }
    if (delay !== null) {
      let id = setInterval(tick, delay);
      return () => clearInterval(id);
    }
  }, [delay]);
}
.dot {
  position: absolute;
  width: 16px;
  height: 16px;
  border-radius: 100%;
  background: red;
  transition: transform 1s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.26.0/moment.min.js"></script>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root" />

Upvotes: 2

Related Questions