React倒计时组件在输入框变更时意外重渲染重置问题排查
问题根源分析
你的倒计时组件在输入框输入时意外重置,核心问题出在AgapeCountdown组件中date属性的计算方式上:
// 原代码中每次父组件渲染都会重新计算这个值 date={Date.now() + duration}
当你在输入框输入内容时,父组件LoginStep2的otp状态会更新,触发父组件重新渲染。此时Date.now() + duration会重新计算为当前时间加上duration,react-countdown组件检测到date prop发生变化,就会自动重置倒计时——这和key无关,哪怕你没改restartKey,只要date变了,倒计时就会重启。
解决方案
修改AgapeCountdown组件,把date的计算和restartKey绑定,只有当需要重置倒计时时才更新目标时间。这里有两种可靠的实现方式:
方式1:使用useMemo缓存目标时间
利用useMemo将目标时间缓存起来,仅在restartKey或duration变化时重新计算:
const AgapeCountdown = ({ duration, children, restartKey, ...props }) => { const classes = useStyles(); // 缓存目标时间,仅依赖restartKey和duration const targetDate = React.useMemo(() => { return Date.now() + duration; }, [restartKey, duration]); const defaultRenderer = ({ hours, minutes, seconds, completed }) => { if (completed) { return children; } return ( <span className={classes.root}> {minutes}:{seconds} </span> ); }; return ( <Countdown renderer={defaultRenderer} date={targetDate} key={restartKey} {...props} /> ); };
方式2:使用useState + useEffect更新目标时间
通过useEffect监听restartKey的变化,手动更新目标时间:
const AgapeCountdown = ({ duration, children, restartKey, ...props }) => { const classes = useStyles(); const [targetDate, setTargetDate] = React.useState(() => Date.now() + duration); // 当restartKey变化时,重置目标时间 React.useEffect(() => { setTargetDate(Date.now() + duration); }, [restartKey, duration]); const defaultRenderer = ({ hours, minutes, seconds, completed }) => { if (completed) { return children; } return ( <span className={classes.root}> {minutes}:{seconds} </span> ); }; return ( <Countdown renderer={defaultRenderer} date={targetDate} key={restartKey} {...props} /> ); };
为什么这样有效?
修改后,targetDate只会在restartKey(触发重置)或duration(时长变化)时更新。父组件因输入框状态变化而重新渲染时,targetDate会保持之前的值,react-countdown不会检测到date prop的变化,自然也就不会重置倒计时了。
内容的提问来源于Stack Exchange,提问作者Joey
相关产品推荐
相关产品推荐

