score:1
there's a fundamental design problem here which is that setinterval
is the wrong tool for keeping time. setinterval
only guarantees that the callback won't run for at least 1000 milliseconds, not that it will run exactly in 1000 milliseconds, so you're going to wind up with drift and skipped times.
i recommend using requestanimationframe
and the date
library or performance.now
to determine when ticks have occurred.
with this set up, you can scale the hour hand proportional to the number of minutes left in the hour with:
(hours + minutes / 60) * 30 + 180
if you want a rougher granularity to the hour hand adjustments, truncate the minutes into 6 distinct chunks:
(hours + floor(minutes / 10) * 10 / 60) * 30 + 180
doing this mathematically is much less messy than looking up the increment points in a hardcoded array.
here's a minimal example which you could use to keep accurate time (i'll leave styling to you):
.hand {
width: 2px;
height: 40%;
background-color: black;
transform-origin: top center;
position: absolute;
border-radius: 3px;
top: 50%;
left: 50%;
}
.analog-clock {
position: relative;
border-radius: 50%;
border: 1px solid #aaa;
height: 120px;
width: 120px;
}
<script type="text/babel" defer>
const {fragment, useeffect, usestate, useref} = react;
const clock = () => {
const [date, setdate] = usestate(new date());
const requestref = useref();
let prevdate = null;
const tick = () => {
const now = new date();
if (prevdate && now.getseconds() !== prevdate.getseconds()) {
setdate(now);
}
prevdate = now;
requestref.current = requestanimationframe(tick);
};
useeffect(() => {
requestref.current = requestanimationframe(tick);
return () => cancelanimationframe(requestref.current);
}, []);
const pad = n => n.tostring().padstart(2, 0);
const computehourdeg = date =>
(date.gethours() + ~~(date.getminutes() / 10) * 10 / 60) * 30 + 180
;
return (
<fragment>
<div classname="analog-clock">
<div
classname="hand"
style={{transform: `rotate(${6 * date.getseconds() + 180}deg)`}}
></div>
<div
classname="hand"
style={{transform: `rotate(${6 * date.getminutes() + 180}deg)`}}
></div>
<div
classname="hand"
style={{background: "red",
height: "30%",
transform: `rotate(${computehourdeg(date)}deg)`}}
></div>
</div>
<h3>
{pad(date.gethours())}:
{pad(date.getminutes())}:
{pad(date.getseconds())}
</h3>
</fragment>
);
};
reactdom.render(<clock />, document.body);
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
here's a sped-up version with a mocked date
object to illustrate that it's working correctly:
.hand {
width: 2px;
height: 40%;
background-color: black;
transform-origin: top center;
position: absolute;
border-radius: 3px;
top: 50%;
left: 50%;
}
.analog-clock {
position: relative;
border-radius: 50%;
border: 1px solid #aaa;
height: 120px;
width: 120px;
}
<script type="text/babel" defer>
const {fragment, useeffect, usestate, useref} = react;
const speedms = 5;
class mockdate {
static second = 0;
static minute = 0;
static hour = 0;
constructor() {
this.second = mockdate.second;
this.minute = mockdate.minute;
this.hour = mockdate.hour;
}
getseconds() {
return this.second;
}
getminutes() {
return this.minute;
}
gethours() {
return this.hour || 12;
}
}
setinterval(() => {
if (++mockdate.second === 60) {
mockdate.second = 0;
if (++mockdate.minute === 60) {
mockdate.minute = 0;
mockdate.hour = (mockdate.hour + 1) % 12;
}
}
}, speedms);
const clock = () => {
const [date, setdate] = usestate(new mockdate());
const requestref = useref();
let prevdate = null;
const tick = () => {
const now = new mockdate();
if (prevdate && now.getseconds() !== prevdate.getseconds()) {
setdate(now);
}
prevdate = now;
requestref.current = requestanimationframe(tick);
};
useeffect(() => {
requestref.current = requestanimationframe(tick);
return () => cancelanimationframe(requestref.current);
}, []);
const pad = n => n.tostring().padstart(2, 0);
const computehourdeg = date =>
(date.gethours() + ~~(date.getminutes() / 10) * 10 / 60) * 30 + 180
;
return (
<fragment>
<div classname="analog-clock">
<div
classname="hand"
style={{transform: `rotate(${6 * date.getseconds() + 180}deg)`}}
></div>
<div
classname="hand"
style={{transform: `rotate(${6 * date.getminutes() + 180}deg)`}}
></div>
<div
classname="hand"
style={{background: "red",
height: "30%",
transform: `rotate(${computehourdeg(date)}deg)`}}
></div>
</div>
<h3>
{pad(date.gethours())}:
{pad(date.getminutes())}:
{pad(date.getseconds())}
</h3>
</fragment>
);
};
reactdom.render(<clock />, document.body);
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
Source: stackoverflow.com
Related Query
- setState does not update state immediately inside setInterval
- Can not update state inside setInterval in react hook
- Calling setState with nested object does not update state correctly
- React hooks - setState does not update state properties
- ReactJS - SetState does not update the state when the state variable is a number
- Redux does not update state immediately
- PrevState does not update state value immediately in React JS
- React Hooks: updating state using useState does not update the state immediately
- setInterval in react does not update the setState
- React cannot set state inside useEffect does not update state in the current cycle but updates state in the next cycle. What could be causing this?
- React setState does not update a state array value
- useState React Hook set method does not update state immediately in onChange()
- React useEffect: setState in return function does not update state in time
- setState inside for loop does not update the state: React+Typescript
- setState does not update state
- React-UseState hook-> state update does not re-render the page immediately
- React hooks - setState does not update some state properties
- setState does not update array state in React Js
- Axios does not update state immediately
- React hooks: Set state 'ModalVisible' but state does not update immediately
- Why does setState not change state inside useEffect?
- setState does not update inside intervalRef
- Why does calling react setState method not mutate the state immediately?
- setState doesn't update the state immediately
- How do I update the state (using ReactJS) if I should not call setState in componentWillUpdate?
- React does not refresh after an update on the state (an array of objects)
- useState in useEffect does not update state
- React js changing state does not update component
- setState call inside a custom hook is not updating the state
- React setState does not set state during a while loop
More Query from same tag
- How to set .next-folder in another folder?
- How to have a React child component call a function from a parent component
- Migrating react-router v3 to v4
- The context `router` is marked as required in `Link`, but its value is `undefined`
- Material-UI dialog overlay?
- How to test react useContext useReducer dispatch in component
- React socket io client emitting twice to node server
- Include some node_modules directories in Babel 7
- useEffect() vs setTimeout() for side effects
- React unexpected token { } when trying to loop inside render
- reactjs: getting error after importing headroom
- Permission denied. Could not perform this operation when using react-firebase-file-uploader
- Removing children from Array inside ScrollView always deletes last item
- How to set/change Field value from external user action 🏁 React Final Form
- Wistia playback in react-player causes error "The XMLHttpRequeset constructor has been tampered with"
- target specific HTML element from an object that is mapped
- Link Props to State ReactJS
- How do I create a dynamic variable name in React?
- Initialize materializecss component in React
- Why is my fixed navbar ontop of my sticky navbar when i coded it in the bottom?
- How do I set profile image as first letters of first and last name?
- Retrieve data from input and pass to redux state
- Use material ui svg icons as background image
- How to fetch only one value in react js?
- How to apply global styling to a react component library?
- How to take the result from a fetch request and insert data into jsx?
- How to document javascript unit test files using jsdoc?
- Why will my fetch API call map one nested objects, but not the other?
- how do i toggle disabled between two buttons in react map
- Handling event method with parameter without inserting parameter