React/JS面试计数器实现方案优化咨询
面试计数器任务优化实现
面试任务要求
- 从0开始,每次将计数加1,直到达到10
- 实现一个函数,当数值大于0时,每次减2直到变为0,数值不能小于0
- 实现一个函数,每次将计数加2,直到达到10
原实现代码
import React, { useState, useEffect } from "react"; export default function App() { const [count, setCount] = useState(0); const [incrementBy1, SetIncBy1] = useState(false); const [incrementBy2, SetIncBy2] = useState(false); const [decrementBy2, SetDecBy2] = useState(false); const [reset, setReset] = useState(false); const addBy1 = () => { setCount((count) => count + 1); }; const addBy2 = () => { setCount((count) => count + 2); }; const subBy2 = () => { setCount((count) => count - 2); }; useEffect(() => { if (count < 10 && incrementBy1 && !reset) { setTimeout(addBy1, 1000); // setReset(false); } if (count < 10 && incrementBy2 && !reset) { setTimeout(addBy2, 1000); // setReset(false); } if (count > 0 && count % 2 === 0 && decrementBy2) { setTimeout(subBy2, 1000); setReset(false); } if ( count > 0 && !reset && !incrementBy1 && !incrementBy2 && !decrementBy2 ) { setReset(true); } if (count > 0 && reset && !incrementBy1 && !incrementBy2 && !decrementBy2) { setReset(false); setCount(0); } if (count === 0 && decrementBy2) { SetDecBy2(false); setReset(false); } if (count < 0) { setCount(0); } console.log(incrementBy2, reset); }, [count, incrementBy1, incrementBy2, decrementBy2, reset]); const startIncrementCounter = () => { if (SetIncBy2) { SetIncBy2(false); } if (SetDecBy2) { SetDecBy2(false); } SetIncBy1(true); }; const startDecrementBy2 = () => { if (SetIncBy2) { SetIncBy2(false); } if (SetIncBy1) { SetIncBy1(false); } SetDecBy2(true); }; const startIncrementBy2 = () => { if (SetIncBy1) { SetIncBy1(false); } if (SetDecBy2) { SetDecBy2(false); } SetIncBy2(true); }; const handleReset = () => { SetIncBy1(false); SetIncBy2(false); SetDecBy2(false); setReset(true); setCount(0); }; return ( <div className="App" style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", width: "100vw" }} > <h1>Counter!</h1> <h2>{count}</h2> <div style={{ display: "flex", alignItems: "center", justifyContent: "space-evenly", maxWidth: 600 }} > <button disabled={incrementBy1 || incrementBy2 || decrementBy2} onClick={startIncrementCounter} > Start Counter </button> <button disabled={count === 0} onClick={startDecrementBy2}> Decrement By 2 </button> <button disabled={ incrementBy1 || incrementBy2 || decrementBy2 || count % 2 !== 0 } onClick={startIncrementBy2} > Increment By 2 </button> <button disabled={ (!incrementBy1 && !incrementBy2 && !decrementBy2) || count === 0 } onClick={handleReset} > reset </button> </div> </div> </div> ); }
优化思路与实现
原代码存在状态冗余、useEffect逻辑复杂、未清理定时器可能引发异常等问题,下面是更简洁易维护的优化版本:
优化点说明
- 合并状态:用单个
currentAction状态替代多个布尔状态,明确当前执行的操作类型(none/inc1/inc2/dec2) - 定时器管理:用
useRef存储定时器ID,在组件卸载或操作切换时清理定时器,避免内存泄漏和重复触发 - 逻辑拆分:将每个操作的执行逻辑封装,代码结构更清晰
- 简化判断:按钮禁用状态基于
currentAction和count直接判断,减少冗余逻辑
优化后的代码
import React, { useState, useEffect, useRef } from "react"; export default function App() { const [count, setCount] = useState(0); const [currentAction, setCurrentAction] = useState('none'); // none/inc1/inc2/dec2 const timerRef = useRef(null); // 执行计数操作 const executeAction = () => { switch(currentAction) { case 'inc1': setCount(prev => { const newCount = prev + 1; // 达到10时停止操作 if(newCount >= 10) setCurrentAction('none'); return newCount; }); break; case 'inc2': setCount(prev => { const newCount = prev + 2; if(newCount >= 10) setCurrentAction('none'); // 确保不超过10 return Math.min(newCount, 10); }); break; case 'dec2': setCount(prev => { const newCount = prev - 2; // 到达0时停止操作 if(newCount <= 0) { setCurrentAction('none'); return 0; } return newCount; }); break; default: break; } }; // 启动/切换操作 useEffect(() => { // 清理之前的定时器 if(timerRef.current) clearTimeout(timerRef.current); // 当前有操作时启动定时器 if(currentAction !== 'none') { timerRef.current = setTimeout(executeAction, 1000); } // 组件卸载时清理定时器 return () => { if(timerRef.current) clearTimeout(timerRef.current); }; }, [currentAction, count]); // 开始加1操作 const startInc1 = () => setCurrentAction('inc1'); // 开始加2操作 const startInc2 = () => setCurrentAction('inc2'); // 开始减2操作 const startDec2 = () => setCurrentAction('dec2'); // 重置计数器 const handleReset = () => { setCurrentAction('none'); setCount(0); }; return ( <div className="App" style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", width: "100vw", gap: '20px' }} > <h1>Counter!</h1> <h2>{count}</h2> <div style={{ display: "flex", gap: '15px', alignItems: "center" }} > <button disabled={currentAction !== 'none'} onClick={startInc1} > Start Counter (+1) </button> <button disabled={count === 0 || currentAction !== 'none'} onClick={startDec2} > Decrement By 2 </button> <button disabled={ currentAction !== 'none' || count % 2 !== 0 || count >= 10 } onClick={startInc2} > Increment By 2 </button> <button disabled={currentAction === 'none' && count === 0} onClick={handleReset} > Reset </button> </div> </div> ); }
总结
优化后的代码大幅减少了状态数量,逻辑更直观易懂,添加了定时器清理机制避免潜在问题,同时保持了所有需求的实现,更符合React组件的最佳实践,也更容易扩展和维护。
内容的提问来源于stack exchange,提问作者Antony Sanders
相关产品推荐
相关产品推荐

