mirror of
https://github.com/mue/mue.git
synced 2026-07-17 14:04:09 +02:00
refactor(clock): enhance error handling and optimize rendering with memoization
This commit is contained in:
@@ -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 (
|
||||
<ErrorBoundary fallback={<div className="clock-error">Error loading clock</div>}>
|
||||
<Suspense fallback={<div className="clock-loading"></div>}>{renderClock()}</Suspense>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
||||
export default Clock;
|
||||
export default memo(Clock);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = () => {
|
||||
<span className="ampm">{ampm}</span>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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]);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user