diff --git a/packages/core/src/bundle/hooks/useStopwatch/useStopwatch.js b/packages/core/src/bundle/hooks/useStopwatch/useStopwatch.js
index eb05949e..63211c10 100644
--- a/packages/core/src/bundle/hooks/useStopwatch/useStopwatch.js
+++ b/packages/core/src/bundle/hooks/useStopwatch/useStopwatch.js
@@ -1,19 +1,24 @@
-import { useEffect, useState } from 'react';
-const getStopwatchTime = (time) => {
- if (!time)
+import { useState } from 'react';
+import { useInterval } from '../useInterval/useInterval';
+const getStopwatchTime = (count) => {
+ if (!count)
return {
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
+ milliseconds: 0,
count: 0
};
- const days = Math.floor(time / 86400);
- const hours = Math.floor((time % 86400) / 3600);
- const minutes = Math.floor((time % 3600) / 60);
- const seconds = Math.floor(time % 60);
- return { days, hours, minutes, seconds, count: time };
+ const totalSeconds = Math.floor(count / 1000);
+ const days = Math.floor(totalSeconds / 86400);
+ const hours = Math.floor((totalSeconds % 86400) / 3600);
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
+ const seconds = Math.floor(totalSeconds % 60);
+ const milliseconds = count % 1000;
+ return { days, hours, minutes, seconds, milliseconds, count };
};
+const getMillsDiffOrZero = (millis) => (Date.now() - millis > 0 ? Date.now() - millis : 0);
/**
* @name useStopwatch
* @description - Hook that creates a stopwatch functionality
@@ -21,74 +26,57 @@ const getStopwatchTime = (time) => {
*
* @overload
* @param {number} [initialTime=0] The initial time of the timer
- * @param {boolean} [options.enabled=true] The enabled state of the timer
+ * @param {boolean} [options.immediately=false] The enabled state of the timer
+ * @param {number} [options.updateInterval=1000] The update interval of the timer
* @returns {UseStopwatchReturn} An object containing the current time and functions to interact with the timer
*
* @example
- * const { seconds, minutes, start, pause, reset } = useStopwatch(1000, { enabled: false });
+ * const { milliseconds, seconds, minutes, start, pause, reset } = useStopwatch(1000, { immediately: false, updateInterval: 1000 });
*
* @overload
* @param {number} [options.initialTime=0] -The initial time of the timer
- * @param {boolean} [options.enabled=true] The enabled state of the timer
+ * @param {boolean} [options.immediately=true] The enabled state of the timer
+ * @param {number} [options.updateInterval=1000] The update interval of the timer
* @returns {UseStopwatchReturn} An object containing the current time and functions to interact with the timer
*
* @example
- * const { seconds, minutes, start, pause, reset } = useStopwatch({ initialTime: 1000, enabled: false });
+ * const { milliseconds, seconds, minutes, start, pause, reset } = useStopwatch({ initialTime: 1000, immediately: false, updateInterval: 1000 });
*/
export const useStopwatch = (...params) => {
const initialTime = (typeof params[0] === 'number' ? params[0] : params[0]?.initialTime) ?? 0;
const options = typeof params[0] === 'number' ? params[1] : params[0];
const immediately = options?.immediately ?? false;
- const [time, setTime] = useState(getStopwatchTime(initialTime));
- const [paused, setPaused] = useState(!immediately && !initialTime);
- useEffect(() => {
- if (paused) return;
- const onInterval = () => {
- setTime((prevTime) => {
- const updatedCount = prevTime.count + 1;
- if (updatedCount % 60 === 0) {
- return {
- ...prevTime,
- minutes: prevTime.minutes + 1,
- seconds: 0,
- count: updatedCount
- };
- }
- if (updatedCount % (60 * 60) === 0) {
- return {
- ...prevTime,
- hours: prevTime.hours + 1,
- minutes: 0,
- seconds: 0,
- count: updatedCount
- };
- }
- if (updatedCount % (60 * 60 * 24) === 0) {
- return {
- ...prevTime,
- days: prevTime.days + 1,
- hours: 0,
- minutes: 0,
- seconds: 0,
- count: updatedCount
- };
- }
- return {
- ...prevTime,
- seconds: prevTime.seconds + 1,
- count: updatedCount
- };
- });
- };
- const interval = setInterval(() => onInterval(), 1000);
- return () => clearInterval(interval);
- }, [paused]);
+ const updateInterval = options?.updateInterval ?? 1000;
+ const [milliseconds, setMilliseconds] = useState(initialTime);
+ const [timestamp, setTimestamp] = useState(Date.now() - initialTime);
+ const interval = useInterval(
+ () => setMilliseconds(getMillsDiffOrZero(timestamp)),
+ updateInterval,
+ {
+ immediately
+ }
+ );
+ const start = () => {
+ if (interval.active) return;
+ setTimestamp(new Date().getTime() - milliseconds);
+ interval.resume();
+ };
+ const pause = () => {
+ if (!interval.active) return;
+ setMilliseconds(getMillsDiffOrZero(timestamp));
+ interval.pause();
+ };
+ const reset = () => {
+ setMilliseconds(initialTime);
+ setTimestamp(Date.now() - initialTime);
+ interval.resume();
+ };
return {
- ...time,
- paused,
- pause: () => setPaused(true),
- start: () => setPaused(false),
- reset: () => setTime(getStopwatchTime(initialTime)),
- toggle: () => setPaused((prevPause) => !prevPause)
+ ...getStopwatchTime(milliseconds),
+ paused: !interval.active,
+ pause,
+ start,
+ reset,
+ toggle: () => (interval.active ? pause() : start())
};
};
diff --git a/packages/core/src/hooks/useStopwatch/useStopwatch.demo.tsx b/packages/core/src/hooks/useStopwatch/useStopwatch.demo.tsx
index 2dd772cc..18376018 100644
--- a/packages/core/src/hooks/useStopwatch/useStopwatch.demo.tsx
+++ b/packages/core/src/hooks/useStopwatch/useStopwatch.demo.tsx
@@ -1,12 +1,15 @@
import { useStopwatch } from '@siberiacancode/reactuse';
const Demo = () => {
- const stopwatch = useStopwatch();
+ const stopwatch = useStopwatch({
+ updateInterval: 100
+ });
return (
- {stopwatch.minutes} m:{stopwatch.seconds} s
+ {stopwatch.minutes} m:{stopwatch.seconds} s:
+ {String(stopwatch.milliseconds).padStart(3, '0')} ms