diff --git a/src/features/time/Clock.jsx b/src/features/time/Clock.jsx
index 42f02376..acf27dae 100644
--- a/src/features/time/Clock.jsx
+++ b/src/features/time/Clock.jsx
@@ -1,10 +1,11 @@
-import { useState, useEffect } from 'react';
+import { useState, useEffect, Suspense, memo } from 'react';
import { AnalogClock } from './components/AnalogClock';
import { VerticalClock } from './components/VerticalClock';
import { DigitalClock } from './components/DigitalClock';
import { PercentageClock } from './components/PercentageClock';
import EventBus from 'utils/eventbus';
import defaults from './options/default';
+import ErrorBoundary from '../../ErrorBoundary';
import 'react-clock/dist/Clock.css';
import './clock.scss';
@@ -49,7 +50,11 @@ const Clock = () => {
}
};
- return renderClock();
+ return (
+ Error loading clock}>
+ }>{renderClock()}
+
+ );
};
-export default Clock;
+export default memo(Clock);
diff --git a/src/features/time/clock.scss b/src/features/time/clock.scss
index 7513c6c1..10e39fce 100644
--- a/src/features/time/clock.scss
+++ b/src/features/time/clock.scss
@@ -61,3 +61,28 @@
line-height: 0;
}
}
+
+.clock-loading {
+ width: 4em;
+ height: 1.5em;
+ background: rgba(255, 255, 255, 0.1);
+ border-radius: 4px;
+ animation: pulse 1.5s infinite ease-in-out;
+}
+
+.clock-error {
+ color: #ff6b6b;
+ font-size: 1em;
+}
+
+@keyframes pulse {
+ 0% {
+ opacity: 0.6;
+ }
+ 50% {
+ opacity: 0.3;
+ }
+ 100% {
+ opacity: 0.6;
+ }
+}
diff --git a/src/features/time/components/DigitalClock.jsx b/src/features/time/components/DigitalClock.jsx
index e7a6d7be..95ffe729 100644
--- a/src/features/time/components/DigitalClock.jsx
+++ b/src/features/time/components/DigitalClock.jsx
@@ -1,18 +1,28 @@
-import React, { useState } from 'react';
+import React, { useState, useMemo } from 'react';
import { useTimeUpdate } from '../hooks/useTimeUpdate';
import { useClockZoom } from '../hooks/useClockZoom';
import { convertTimezone } from 'utils/date';
-export const DigitalClock = () => {
+// Add memoization of time settings
+const getTimeSettings = () => {
+ const settings = {
+ timeformat: localStorage.getItem('timeformat'),
+ timezone: localStorage.getItem('timezone'),
+ zero: localStorage.getItem('zero'),
+ showSeconds: localStorage.getItem('seconds') === 'true',
+ };
+ return settings;
+};
+
+export const DigitalClock = React.memo(() => {
const [time, setTime] = useState('');
const [ampm, setAmpm] = useState('');
const { elementRef } = useClockZoom();
+ const timeSettings = useMemo(getTimeSettings, []);
const updateTime = () => {
let now = new Date();
- const timezone = localStorage.getItem('timezone');
- const zero = localStorage.getItem('zero');
- const showSeconds = localStorage.getItem('seconds') === 'true';
+ const { timezone, zero, showSeconds, timeformat } = timeSettings;
if (timezone && timezone !== 'auto') {
now = convertTimezone(now, timezone);
@@ -23,7 +33,7 @@ export const DigitalClock = () => {
const minutes = ('00' + now.getMinutes()).slice(-2);
const seconds = showSeconds ? `:${('00' + now.getSeconds()).slice(-2)}` : '';
- if (localStorage.getItem('timeformat') === 'twentyfourhour') {
+ if (timeformat === 'twentyfourhour') {
timeStr =
zero === 'false'
? `${hours}:${minutes}${seconds}`
@@ -52,4 +62,4 @@ export const DigitalClock = () => {
{ampm}
);
-};
+});
diff --git a/src/features/time/hooks/useTimeUpdate.js b/src/features/time/hooks/useTimeUpdate.js
index 997e934b..f37479de 100644
--- a/src/features/time/hooks/useTimeUpdate.js
+++ b/src/features/time/hooks/useTimeUpdate.js
@@ -1,28 +1,20 @@
import { useEffect, useRef } from 'react';
-export const useTimeUpdate = (updateFn) => {
- const timerRef = useRef(null);
+export const useTimeUpdate = (callback, interval = 1000) => {
+ const savedCallback = useRef(callback);
useEffect(() => {
- const startTime = (initialDelay = null) => {
- const showSeconds = localStorage.getItem('seconds') === 'true';
- const delay =
- initialDelay ?? (showSeconds ? 1000 - (Date.now() % 1000) : 60000 - (Date.now() % 60000));
+ savedCallback.current = callback;
+ }, [callback]);
- if (timerRef.current) {
- clearTimeout(timerRef.current);
- }
+ useEffect(() => {
+ // Immediately execute callback to avoid delay
+ savedCallback.current();
- updateFn();
- timerRef.current = setTimeout(() => startTime(), delay);
- };
+ const id = setInterval(() => {
+ savedCallback.current();
+ }, interval);
- startTime(0);
-
- return () => {
- if (timerRef.current) {
- clearTimeout(timerRef.current);
- }
- };
- }, [updateFn]);
+ return () => clearInterval(id);
+ }, [interval]);
};