Reputation: 10264
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
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