React类转函数组件如何用useEffect实现setTimeout并避免首次触发
问题原因
你当前写法的问题在于useEffect会在组件首次渲染、以及依赖项isCopied每次变化时都执行,首次渲染时isCopied初始值为false,会直接触发一次无意义的定时器,同时未清理的定时器会导致连续点击时状态重置逻辑混乱。
方案1:修改现有useEffect逻辑(最小改动兼容写法)
只需要给useEffect加状态判断和定时器清理逻辑即可:
function ColorBox(props) { const [isCopied, setIsCopied] = useState(false) useEffect(() => { // 只有复制激活状态下才启动重置定时器 if (isCopied) { const timerId = setTimeout(() => setIsCopied(false), 1500) // 依赖变化/组件卸载时清理旧定时器 return () => clearTimeout(timerId) } }, [isCopied]) const changeCopyState = () => { setIsCopied(true) }; // 其余组件逻辑 }
这种写法改动手笔最小,首次渲染时isCopied为false不会触发定时器,同时支持其他逻辑修改isCopied后也能自动重置状态。
方案2:无需useEffect的更直观写法(贴合原类组件逻辑)
如果isCopied只会在点击复制按钮时修改,可以直接在触发函数里处理定时器,逻辑更清晰:
function ColorBox(props) { const [isCopied, setIsCopied] = useState(false) // 用useRef存储定时器id,避免渲染导致变量丢失 const timerRef = useRef(null) const changeCopyState = () => { // 连续点击时清理旧定时器,避免重置时间异常 if (timerRef.current) clearTimeout(timerRef.current) setIsCopied(true) timerRef.current = setTimeout(() => { setIsCopied(false) }, 1500) }; // 组件卸载时清理残留定时器 useEffect(() => { return () => timerRef.current && clearTimeout(timerRef.current) }, []) // 其余组件逻辑 }
这种写法完全规避了useEffect首次执行的问题,和你原类组件的逻辑一致性更高。
内容的提问来源于stack exchange,提问作者yevg555
相关产品推荐
相关产品推荐

