前端手撕题—倒计时组件
#一人分享一道面试手撕题#
得物、拼多多经常考,倒计时组件
1.倒计时组件
2.如何实现精确计时(setInterval 1s先就update以前知道写但没考虑到为什么,时间戳同步)
// Countdown.jsx
import React, { useEffect, useState, useRef } from 'react';
/**
* props:
* - endAt: number (timestamp ms) 或 Date
* - onFinish?: () => void
* - tickMs?: number (minimal tick granularity, default 1000)
*/
export default function Countdown({ endAt, onFinish, tickMs = 1000 }) {
const endTs = typeof endAt === 'number' ? endAt : endAt.getTime();
const [remaining, setRemaining] = useState(Math.max(0, endTs - Date.now()));
const mounted = useRef(true);
useEffect(() => {
mounted.current = true;
// initial sync
function update() {
const now = Date.now();
const rem = Math.max(0, endTs - now);
if (!mounted.current) return;
setRemaining(rem);
if (rem === 0) {
onFinish?.();
return;
}
// Align next update to wall-clock second boundary (or tickMs)
const delay = Math.min(
tickMs,
1000 - (now % 1000) // align to next second for nicer UX
);
// If <1s left, use requestAnimationFrame for smoothness
if (rem <= 1000) {
requestAnimationFrame(update);
} else {
setTimeout(update, delay);
}
}
update();
return () => {
mounted.current = false;
};
}, [endTs, onFinish, tickMs]);
const sec = Math.ceil(remaining / 1000);
const mm = Math.floor(sec / 60);
const ss = sec % 60;
return (
<div>
{mm}:{String(ss).padStart(2, '0')}
</div>
);
}
得物、拼多多经常考,倒计时组件
1.倒计时组件
2.如何实现精确计时(setInterval 1s先就update以前知道写但没考虑到为什么,时间戳同步)
// Countdown.jsx
import React, { useEffect, useState, useRef } from 'react';
/**
* props:
* - endAt: number (timestamp ms) 或 Date
* - onFinish?: () => void
* - tickMs?: number (minimal tick granularity, default 1000)
*/
export default function Countdown({ endAt, onFinish, tickMs = 1000 }) {
const endTs = typeof endAt === 'number' ? endAt : endAt.getTime();
const [remaining, setRemaining] = useState(Math.max(0, endTs - Date.now()));
const mounted = useRef(true);
useEffect(() => {
mounted.current = true;
// initial sync
function update() {
const now = Date.now();
const rem = Math.max(0, endTs - now);
if (!mounted.current) return;
setRemaining(rem);
if (rem === 0) {
onFinish?.();
return;
}
// Align next update to wall-clock second boundary (or tickMs)
const delay = Math.min(
tickMs,
1000 - (now % 1000) // align to next second for nicer UX
);
// If <1s left, use requestAnimationFrame for smoothness
if (rem <= 1000) {
requestAnimationFrame(update);
} else {
setTimeout(update, delay);
}
}
update();
return () => {
mounted.current = false;
};
}, [endTs, onFinish, tickMs]);
const sec = Math.ceil(remaining / 1000);
const mm = Math.floor(sec / 60);
const ss = sec % 60;
return (
<div>
{mm}:{String(ss).padStart(2, '0')}
</div>
);
}
全部评论
相关推荐
牛可乐:老师文笔太好了 点赞 评论 收藏
分享

